User Tools

Site Tools


add_temperature_sensor_in_domoticz

This is an old revision of the document!


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.

#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, not the ID of your virtual sensor.

Update temperature with a script

Domoticz provide 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.

This is the source code of my own script. The script read the temperature value by asking the arduino to write the value to the serial line.

-- demo time script
-- script names have three name components: script_trigger_name.lua
-- trigger can be 'time' or 'device', name can be any string
-- domoticz will execute all time and device triggers when the relevant trigger occurs
-- 
-- copy this script and change the "name" part, all scripts named "demo" are ignored. 
--
-- Make sure the encoding is UTF8 of the file
--
-- ingests tables: otherdevices,otherdevices_svalues
-- 
-- otherdevices and otherdevices_svalues are two item array for all devices: 
--   otherdevices['yourotherdevicename']="On"
--	otherdevices_svalues['yourotherthermometer'] = string of svalues
--
-- Based on your logic, fill the commandArray with device commands. Device name is case sensitive. 
--
-- Always, and I repeat ALWAYS start by checking for a state.
-- If you would only specify commandArray['AnotherDevice']='On', every time trigger (e.g. every minute) will switch AnotherDevice on.
--
-- The print command will output lua print statements to the domoticz log for debugging.
-- List all otherdevices states for debugging: 
--   for i, v in pairs(otherdevices) do print(i, v) end
-- List all otherdevices svalues for debugging: 
--   for i, v in pairs(otherdevices_svalues) do print(i, v) end
 
-- 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 " .. tonumber(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 json_value = JSON:decode(read_value)
while json_value.channel==0 do
	wserial:write("r")
	wserial:flush()
	read_value = rserial:read()
	json_value = JSON:decode(read_value)	
end
 
-- Update the sensor value with the new temperature
commandArray['UpdateDevice']=deviceNum..'|0|'..json_value.temp/10
 
return commandArray

The Temperature dashboard

Reference

add_temperature_sensor_in_domoticz.1459713413.txt.gz · Last modified: 2016/04/03 21:56 by sgripon