User Tools

Site Tools


add_temperature_sensor_in_domoticz

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:

  1. Open a serial connection on the client
  2. Wait 2 seconds that the Arduino Uno reset
  3. The serial connection must remain open
  4. 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

Share this page:

add_temperature_sensor_in_domoticz.txt · Last modified: 2016/11/11 20:01 by sgripon