通过米家自动化极客版实现“自适应节律照明”功能(色温根据日出日落时间变化)
为什么想做这个?
起因是看到一期介绍蓝牙Mesh2.0射灯的视频,里面提到这个产品有节律照明的功能,乍一听确实是挺不错的
什么是节律照明呢?
确实挺不错,结果一看价格(135一个射灯)……打扰了,这功能我用自动化实现一下得了……
并且,中枢自动化还支持数学函数运算,更能做到根据每天日出日落时间实现不同的节律变化(例如冬季白天会更短、日落更早,夏季反之),比起视频中展示的手动设置要更加精准且符合自然规律。
硬件需求
小米中枢网关 / 小米路由器BE6500Pro 或后续发售的其他带有中枢网关功能的产品
PS:理论上,用普通米家自动化也能实现,但那样实在太麻烦了……支持调节色温的照明产品(并且其能够被中枢控制)
逻辑设计
这部分要考虑的就很多了,首先要根据时间段设定合适的色温,还要让变化过程看起来自然流畅,同时不能影响正常的开关灯操作(要加入当前状态检测而不是无脑定时),因为某些灯在被控制色温的时候,会自动打开灯光(例如我家的灯带)。
那么如何检查自己灯是否存在这个问题?非常简单,新建一个自动化,然后创建这样一个逻辑,关掉要测试的灯,右上角保存即可,如果发现灯亮了,那么说明需要做当前状态检测。
接下来,就要考虑一下色温的变化问题了。
可以看到,一天当中色温的变化实际是非线性变化的,这就要用到中枢的数学函数运算功能了。
理论存在,实践开始
创建全局变量作为开关
或许有时候我们不希望开启节律照明功能,就希望切换到一个固定的色温,这时候一个前置开关就很重要了。
参考程序设计中Bool
对应的值,我们定义0
为False
(关闭),1
为True
(开启)。
确保自动化程序的鲁棒性
一旦此变量的值不等于0,就将其设为1,防止出现其他的意外值导致后面的条件判断出错。
利用定时功能确定日落日出时间
这部分很简单,使用定时中自带的日出日落即可,尽管这样在之后的自动化进程中使用的是前一天的日出日落时间,但也已经足够跟上季节的变化,比起写死的定时来说要准确的多了。
由于采用定时器的方式获取日出日落时间,所以变量预设值是必须的,否则在下一次日出日落之前变量的值都是不正确的;
我这里预设的值分别为:5,30,18,30(即预设5:30日出,18:30日落)
至于经纬度,你可以使用自带的“获取经纬度”获取(取决于你浏览器的网络环境),也可以使用一些地图API获取,例如:
简化变量
这里我们再定义3个变量分别表示重要的3个时间点(以分钟为单位),以简化后面的计算过程,分别是:
t_sunrise
:日出的时间点t_sunset
:日落的时间点t_now
:当前时间点
注意这个时候t_sunrise
和t_sunset
以及t_midday
变量都是不会更新的,因为没有被定时触发,可以直接将本规则启用时连接到他们的前端,手动更新一次,或手动设置一个初始值,防止后面要用到这些变量的时候出错。
手动设置参考值:
色温计算
这里使用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_sunrise
和t_sunset
之内时,色温计算的表达式为:
color_temp = 2700 +(6500-2700)*sin(pi()*($t_now-$t_sunrise)/($t_sunset-$t_sunrise))
一旦时间超出此范围,就不再设定色温。
CRAZY IDEA
或许以后会出现色温传感器这样的设备?让室内照明也能精准对齐室外色温,更符合所在地理位置的节律?
但这样在户外工作的传感器,防水、电池寿命会是一个挺大的问题……
- 感谢你赐予我前进的力量