Sensor fusion: Tempest Weather station + Kauf Bulb

December 8, 2023

A fall can be a seriously bad event. Permanently debilitating. At our house the stairwell is sometimes darker than I would like, and I decided to do something about it.

I recently purchased a KAUF brand bulb to try out. I picked it specifically because the manufacturer supports open software. Almost all of the internet of things manufacturers force you into their walled garden. You have no other choice but to buy from them. I don’t know about you, but I resent that.

To get back to the tech, the KAUF bulb comes preloaded with ESPHome firmware so it will plug and play with the Home Assistant open source software. I don’t use Home Assistant myself, but that’s another digression. Home Assistant is too complex, too bloated, and shows every sign of becoming more of both.

KAUF does mention the bulb can be easily flashed with Tasmota though. That’s more like it! Tasmota is a lot smaller and includes features for edge computing, and more importantly for security. It’s not a good idea to leave your computers unsecured, even if they are really small. (Cue bad horror movie here!)

We already have a Tempest home weather station by weatherflow. It regularly broadcasts the weather readings over UDP on our home network. One of the readings is the Luminance outside. Every five minutes I get a reading of how sunny and bright it is.

It occurred to me the ambient light in the stairwell is directly related to the Luminance outside. So, if I were to connect the bulb to the weather station it could brighten up the dark stairwell when it was really needed. I can adjust the color and the brightness of the bulb directly as well. So began a quest to create a smart safety light.

I use Node-Red and MQTT to control the house, so below is a function node with javascript code to implement the bulb control. If the day is partly cloudy the luminance can vary considerably, so the previous three readings are retained in the flow context memory. If any of them is too dark it turns on the light. If none are too dark the lamp is shut off. If the state of the bulb is unchanged it does not hammer the bulb with worthless requests.

Math.min() gets the lowest value in the array of stored values.

payload.obs[0][9] returns the luminance value from the tempest weather station observations.

flow.get() / .set(): gets and sets a value in flow context memory.

Here’s the function node:

// turn on safety light if too dark. Value is in LUX
const tooDark = 8000;

// get history. If not defined initialize to empty array
var luminanceArray = flow.get('luminanceArray') || [];

//node.warn('luminanceArray '+ luminanceArray);

// get state of the bulb
var currentState = Math.min(...luminanceArray) < tooDark;

// luminance Value is in LUX measured outside by tempest weather station
var luminance = Number(msg.payload.obs[0][9]);

// add current value to previous measurements
luminanceArray.push( luminance );

var nextState = Math.min(...luminanceArray) < tooDark;

// keep three newest measurements
if ( luminanceArray.length > 3 )
luminanceArray.splice(0,1);

flow.set( 'luminanceArray', luminanceArray );

// emit a message to be sent via MQTT if the state changed
if (nextState != currentState)
{
//node.warn('send cmnd');
// turn on safety lamp if it's too dark
if (nextState) {
msg.topic = 'cmnd/tasmota_xxx/Backlog';
msg.payload = 'Color1 #28114F0000 ; Dimmer 28 ; Power ON';
}
else {
msg.topic = 'cmnd/tasmota_xxx/POWER';
msg.payload = 'OFF';
}
return msg;
}

//node.warn('nothing to do');
// nothing more to do. End process here
return null;