为什么想做这个?

起因是看到一期介绍蓝牙Mesh2.0射灯的视频,里面提到这个产品有节律照明的功能,乍一听确实是挺不错的

什么是节律照明呢?

确实挺不错,结果一看价格(135一个射灯)……打扰了,这功能我用自动化实现一下得了……

并且,中枢自动化还支持数学函数运算,更能做到根据每天日出日落时间实现不同的节律变化(例如冬季白天会更短、日落更早,夏季反之),比起视频中展示的手动设置要更加精准且符合自然规律。

硬件需求

  • 小米中枢网关 / 小米路由器BE6500Pro 或后续发售的其他带有中枢网关功能的产品
    PS:理论上,用普通米家自动化也能实现,但那样实在太麻烦了……

  • 支持调节色温的照明产品(并且其能够被中枢控制)

逻辑设计

这部分要考虑的就很多了,首先要根据时间段设定合适的色温,还要让变化过程看起来自然流畅,同时不能影响正常的开关灯操作(要加入当前状态检测而不是无脑定时),因为某些灯在被控制色温的时候,会自动打开灯光(例如我家的灯带)。

那么如何检查自己灯是否存在这个问题?非常简单,新建一个自动化,然后创建这样一个逻辑,关掉要测试的灯,右上角保存即可,如果发现灯亮了,那么说明需要做当前状态检测。

接下来,就要考虑一下色温的变化问题了。

揭秘!日常生活十二小时中不为人知的灯光密码

可以看到,一天当中色温的变化实际是非线性变化的,这就要用到中枢的数学函数运算功能了。

理论存在,实践开始

创建全局变量作为开关

或许有时候我们不希望开启节律照明功能,就希望切换到一个固定的色温,这时候一个前置开关就很重要了。

参考程序设计中Bool对应的值,我们定义0False(关闭),1True(开启)。

确保自动化程序的鲁棒性

一旦此变量的值不等于0,就将其设为1,防止出现其他的意外值导致后面的条件判断出错。

利用定时功能确定日落日出时间

这部分很简单,使用定时中自带的日出日落即可,尽管这样在之后的自动化进程中使用的是前一天的日出日落时间,但也已经足够跟上季节的变化,比起写死的定时来说要准确的多了。

由于采用定时器的方式获取日出日落时间,所以变量预设值是必须的,否则在下一次日出日落之前变量的值都是不正确的;
我这里预设的值分别为:5,30,18,30(即预设5:30日出,18:30日落)

至于经纬度,你可以使用自带的“获取经纬度”获取(取决于你浏览器的网络环境),也可以使用一些地图API获取,例如:

https://api.map.baidu.com/lbsapi/getpoint/index.html

简化变量

这里我们再定义3个变量分别表示重要的3个时间点(以分钟为单位),以简化后面的计算过程,分别是:

  • t_sunrise:日出的时间点

  • t_sunset:日落的时间点

  • t_now:当前时间点

注意这个时候t_sunriset_sunset以及t_midday变量都是不会更新的,因为没有被定时触发,可以直接将本规则启用时连接到他们的前端,手动更新一次,或手动设置一个初始值,防止后面要用到这些变量的时候出错。

手动设置参考值:

t_sunrise

t_sunset

330

1110

色温计算

这里使用Python代码简单展示一下计算逻辑:

import datetime
from numpy import arange
# 定义变量
t_sunrise = 330
t_sunset = 1110
t_midday = (t_sunrise + t_sunset)/2
t_now = datetime.datetime.now().hour*60 + datetime.datetime.now().minute
t_nows = arange(0, 1440, 1)
t_now
#%%
import math
# 定义函数
def sin(x):
    return math.sin(x)

def pi():
    return math.pi

# 定义常量
min_color_temp = 2700
max_color_temp = 6500
#%%
from matplotlib import pyplot as plt
import numpy as np

# 计算色温
def calculate_color_temp(t):
    if t <= t_sunrise or t >= t_sunset:
        return min_color_temp
    else:
        return min_color_temp + (max_color_temp - min_color_temp) * sin( pi() * (t - t_sunrise) / (t_sunset - t_sunrise) )

color_temps = [calculate_color_temp(t) for t in t_nows]

# 绘制色温变化曲线
plt.figure(figsize=(10, 6))
plt.plot(t_nows / 60, color_temps, label="Color Temperature", color='orange')
plt.axvline(x=t_sunrise/60, color='blue', linestyle='--', label='Sunrise')
plt.axvline(x=t_sunset/60, color='red', linestyle='--', label='Sunset')
plt.title('Circadian Lighting Color Temperature Throughout the Day')
plt.xlabel('Time of Day (hours)')
plt.ylabel('Color Temperature (K)')
plt.xticks(np.arange(0, 25, 1))
plt.yticks(np.arange(2700, 6600, 500))
plt.grid(True)
plt.legend()
plt.show()

不过,为了在中枢内实现这样的效果,还是需要加一些逻辑判断

当时间在t_sunriset_sunset之内时,色温计算的表达式为:

color_temp = 2700 +(6500-2700)*sin(pi()*($t_now-$t_sunrise)/($t_sunset-$t_sunrise))

一旦时间超出此范围,就不再设定色温。

CRAZY IDEA

或许以后会出现色温传感器这样的设备?让室内照明也能精准对齐室外色温,更符合所在地理位置的节律?

但这样在户外工作的传感器,防水、电池寿命会是一个挺大的问题……