Home Assistant/MySensors quirks
-
I just deployed my Remote Solar (with battery) Moisture Sensor. Once I got all of the subtilties nailed down, two lines of code, read and send, bloomed into over 300 lines!
There were three Home Assistant (HA) related gotchas.
Gotcha 1. getting data from HA.
If you have everything coded right, HA will know about your Arduino, but you have to send a datum for each sensor (child_ids) to get HA to know about the sensors. I do this in setup
But for reasons beyond my understanding, HA won't send anything other than binary. To get around this I send text. That is, the
MyMessage
is of typeV_TEXT
and thepresentation()
isS_INFO
#define CHILD_ID_SAMPLE_INTERVAL 0 MyMessage msgSampleInterval(CHILD_ID_SAMPLE_INTERVAL, V_TEXT); volatile unsigned long SamplePeriod = 20000; // ms to sleep between sensor reads volatile bool SamplePeriodReceived = false; void presentation(){ present(CHILD_ID_SAMPLE_INTERVAL,S_INFO,varName); // sensor 0 wait(REGISTERING_VARIABLES_WAIT); } void setup(){ send(msgSampleInterval.set(SamplePeriod)); wait(MESSAGE_WAIT); } void loop(){ // read data // send data if (SamplePeriodReceived) { SamplePeriodReceived = false; // do something with datum that came from HA } smartSleep(SamplePeriod); } void receive(const MyMessage &message){ switch( message.getSensor() ) { case CHILD_ID_SAMPLE_INTERVAL: // MQTT topic: mysensors-in/177/0/0/0/47 SamplePeriod = message.getLong(); SamplePeriodReceived = true; break; }
What's going on?
- Basic
MyMessage
, but of type V_TEXT - The two variables need to volatile because they can be changed at any time by the background process
receive()
. This variable must be kept up-to-date. present()
is of type S_INFO (see below forvarname)- Send an initial value in
setup()
so that HA knows about the variable - In
loop()
, check periodically to see if a datum came in. This is done because you want to keep thereceive()
routine as short as possible. Also, no sends and no print statements, no long loops, etc. inreceive()
. Anything you can do inloop()
, do it inloop()
.
The data is sent from HA as text. Doesn't matter, the message.getTYPE(); will convert it for you.
Gotcha 2. I use an MQTT gateway. I have a
wait()
after everysend()
. I'm not sure why; my guess is that if you send to fast, the data gets overrun. For sending messages, I use 300mSec. For presentation is use 4000 mSec!!!!Gotch 3. Beauteous! I got it all working. Time to turn
MY_DEBUG
off. To ensure it is off:#ifdef MY_DEBUG #undef MY_DEBUG #endif
It stopped working and, because
MY_DEBUG
was off, I couldn't figure out why. I put it back in, worked fine. It dawned on me that those debug statements took time. I added 200mSec, yes, a full half second! (Lieutenant Commander Data: 0.68 seconds sir. For an android, that is nearly an eternity.)Do not use
delay()
, that stops all processing.wait()
will allow the background process to function, such as receiving data. The syntax forwait()
isbool wait(unsigned long ms, uint8_t cmd, uint8_t msgtype);
which will wait for the first condition to be true, but I am unable to find the cmd or msgtype. To wait for those would be much more elegant.- below
varname
varname This is the name that HA uses in automations, scripts, etc. The problem comes when you have two Arduinos that run the same code. HA appends an arbitrary number to the end of the variable name. This leaves you to root around HA to find out what that was. I programatically append the node number to my varname. varname must be of type
string
(an array of characters the byte after the last character set to 0) as opposed to typeString
. Using typeString
is not advised as it is very easy to add to the String so much that it wipes out memory beyond its bounds. A real bugger to debug, especially if it occurs inreceive()
.- HA script to change interval period to 4001 mSec (assumes varname is "int177"
sequence: - target: entity_id: text.int177 data: value: "4001" action: text.set_value alias: moisture sensor 177 Sample Period 4001 HA mode: single description: Send text to change sample period to 4001
- Basic