一间温室上会挂好几个传感器。温度、湿度、CO2。再加上换气窗、阀门这些会动的东西。
刚装的时候这不是问题。三个就把三个写进代码。问题在三年后来。 温度计坏了,换成另一个产品。那个产品按华氏测。再加一个 CO2 传感器。再加一个阀门。
如果每次都得改控制代码,那这间温室就成了离开装它的人就修不了的东西。
节点自己说自己是什么
这个样例里,每个节点用六个字段声明自己。
printf("%s{\"id\":\"%s\",\"role\":\"%s\",\"kind\":\"%s\","
"\"model\":\"%s\",\"unit\":\"%s\",\"value\":%.1f}",
i ? "," : "", n->id, n->role, n->kind, n->model,
n->unit, n->value);
id · role · kind · model · unit · value。
unit 作为一个字段存在,是关键。 按华氏测的温度计就说华氏。它不会为了别人方便先替你换算成摄氏。硬件只诚实地说自己知道的,对齐这件事在上面做。
对齐的地方只有一处
/// The value moved into the unit the rules use.
///
/// This is the only place in this sample that knows about units, and it
/// decides from the unit a node declared, not from a model number. A sensor
/// nobody has ever heard of still states its unit, so it lands here exactly.
double get canonicalValue {
switch (unit) {
case 'F':
return (value - 32) * 5 / 9;
default:
return value;
}
}
要是按型号分支,这个地方立刻变成一份 清单。每买一个新产品就多一行,而清单上没有的产品进来时,会悄悄地用错值。
看 unit,第一次见的产品也自己对得上。
规则不认识零件号
一条种植规则七行。
Rule(
name: 'vent above 26C',
whenKind: 'temperature',
above: 26.0,
thenKind: 'vent',
setTo: 80.0,
elseSetTo: 0.0,
),
没写是哪个传感器。 也没写是哪个继电器。只有读的值的 种类 和要动的东西的 种类。
不管是 TH-100 还是 FX-200,只要 kind 是 temperature,这条规则就看它。
真的换了一次
装机 A —— 摄氏温度计,三个节点。
A: discovered 3 nodes — t1:temperature:TH-100(C), h1:humidity:HM-20(pct), v1:vent:VT-9(pct)
A: vent above 26C: 26.1 -> v1=80.0


现在把温度计 换成华氏型号,再 加上 一个 CO2 传感器和一个阀门。
=== pass B: probe swapped for a Fahrenheit model, two nodes added ===
server code: unchanged rules: unchanged rebuild: none
B: discovered 5 nodes — t1:temperature:FX-200(F), h1:humidity:HM-20(pct),
c1:co2:CO-5(ppm), v1:vent:VT-9(pct), w1:valve:WV-3(pct)
B: vent above 26C: 26.1 -> v1=80.0 · water below 60% humidity: 62.8 -> w1=0.0


服务端代码没改。规则没改。没有重编译。
而且 vent above 26C 在两次装机里 都是在 26.1 触发的。 因为华氏传感器送来的值在一个地方被搬成了摄氏。没有那一个地方,华氏 79 度就会直接越过 26 度的阈值,换气窗会一直开着。