Table of Contents
Add temperature sensor in Domoticz
Introduction
In a previous post, I have shown how to record temperature from Lexibook ASM30 sensor with Arduino. Now, we will import the temperature in Domoticz.
Assembly
First, prepare the assembly from page Record temperature from Lexibook ASM30 sensor with Arduino. Then, just plug the arduino to the raspberry pi USB.
Arduino
The Arduino sketch
I modified a little bit the previous sketch in order to read from the serial line and send the temperature only when it is requested by client.
- SmartHomeBox_sgripon.ino
#include <RFControl.h> // Save current temperature and channel int temperature = 0; int channel = 0; void setup() { // Initialize serial line Serial.begin(9600); // Start receiving RF signals RFControl::startReceiving(0); } // The function prints current data to the serial line void printData() { Serial.print("{ "); Serial.print("\"temp\": "); Serial.print(temperature); Serial.print(", \"channel\": "); Serial.print(channel); Serial.print(" }\n"); } void loop() { // Decode data when received if(RFControl::hasData()) { unsigned int *timings; unsigned int timings_size; unsigned int pulse_length_divider = RFControl::getPulseLengthDivider(); RFControl::getRaw(&timings, &timings_size); int iTemperatureTmp = 0; int iChannelTmp = 0; for(int i=0; i < timings_size; i++) { unsigned long timing = timings[i] * pulse_length_divider; // Temperature is at bit 16*2 coded in decimal x 10 on 8 bits if( (i >= 16*2) && (i < (16*2 + 8*2)) ) { if(i == 16*2) iTemperatureTmp = 0; if(timing < 1000) { // bit separator, do nothing } else if(timing < 2000) { iTemperatureTmp = iTemperatureTmp<<1; } else if(timing < 5000) { iTemperatureTmp = iTemperatureTmp<<1; iTemperatureTmp++; } } // Sensor Channel is after byte 3, on 2 bits, decimal encoded else if((i >= 24*2) && i <= 26*2) { if(i == 24*2) channel = 0; if(timing < 1000) { // bit separator, do nothing } else if(timing < 2000) { iChannelTmp = iChannelTmp<<1; } else if(timing < 5000) { iChannelTmp = iChannelTmp<<1; iChannelTmp++; } } // Other data else { // Do nothing for now } } temperature = iTemperatureTmp; channel = iChannelTmp; RFControl::continueReceiving(); } if(Serial.available() > 0) { // For now, send data whatever the received command is Serial.read(); // Wait a little delay(500); printData(); } }
The Auto-reset issue
The Arduino Uno automatically reset when the serial line is open by a client. This is due to the DTR signal used by the Arduino to reset. This signal cannot be disabled on the raspberry pi. The official Arduino website gives some hardware tricks to disable the auto-reset. However, I choose here a pure software method as a workaround: the reset is not disabled, but this method allows the serial communication:
- Open a serial connection on the client
- Wait 2 seconds that the Arduino Uno reset
- The serial connection must remain open
- Communicate
This workaround is used in the Domoticz LUA script after.
Domoticz
Create virtual sensor
The first thing to do is to add a dummy device with virtual sensor in Domoticz:
- In Setup/Hardware, add “Dummy” type hardware
- In hardware list, click “Create virtual sensor” next to your dummy hardware.
- Choose “Temperature” for the sensor type
Then, in Setup/Device list, note the ID of your virtual sensor: it must be reused in the LUA script.
Update temperature with a script
Domoticz provides a way to update its data through custom scripts written in LUA language. To use scripts, just create a file called script_time_HardwareName.lua in domoticz installation path domoticz/scripts/lua. The script will be automatically called every minute by Domoticz.
This is the source code of my own script. The script reads the temperature value by asking the arduino to write the value to the serial line. The script use an external library to decode JSON data (see http://regex.info/blog/lua/json).
- script_time_HardwareName.lua
-- Serial port must be configured before opening the file -- stty -F /dev/ttyACM0 9600 local deviceNum = 1 local serialPort = "/dev/ttyACM0" JSON = (loadfile "/home/pi/bin/domoticz/scripts/lua/JSON.lua")() -- one-time load of the routines commandArray = {} -- Open seria port in read and write wserial=io.open(serialPort, "w") rserial=io.open(serialPort, "r") -- Because Arduino auto-reset when a serial line is open, wait the end of reset before doing anything os.execute("sleep 2") -- First send a command to read the temperature. rserial:flush() wserial:write("r") wserial:flush() rserial:read() rserial:flush() -- Do it another time in order to ensure we have a full frame wserial:write("r") wserial:flush() read_value = rserial:read() -- Ask a new read until a signal has been received from the sensor. It should be available within next 30 seconds with this sensor. local nbTries = 0; local json_value = JSON:decode(read_value) while json_value.channel==0 and nbTries < 16 do nbTries = nbTries + 1 os.execute("sleep 2") wserial:write("r") wserial:flush() read_value = rserial:read() json_value = JSON:decode(read_value) end -- Update the sensor value with the new temperature if a temperature has been read if json_value.channel==1 then commandArray['UpdateDevice']=deviceNum..'|0|'..json_value.temp/10 -- print("[DEBUG] Temperature: "..json_value.temp) end return commandArray
The Temperature dashboard
See also
Reference
- Domoticz: https://www.domoticz.com/
- Arduino: Disabling Auto Reset On Serial Connection : http://playground.arduino.cc/Main/DisablingAutoResetOnSerialConnection
- JSON encoding/decoding in LUA by Jeffrey Friedl: http://regex.info/blog/lua/json
Share this page: