New value type V_CUSTOM and example

Moderator: leecollings

Post Reply
User avatar
gizmocuz
Posts: 2394
Joined: Thursday 11 July 2013 18:59
Target OS: Raspberry Pi / ODroid
Domoticz version: beta
Location: Top of the world
Contact:

New value type V_CUSTOM and example

Post by gizmocuz »

There is a new value type in MySensors (1.6 development branch) that can be used for various things.
For Domoticz the implementation is that you can request a sensor value (nValue/sValue) from Domoticz.

As an example i created a LCD sketch (16x2) that displays the outside temperature, the water/gas and power meter values:
MySensors V_Custom
MySensors V_Custom
MySensorsVCustom.PNG (144.52 KiB) Viewed 5183 times
Here is the sketch (a quick hack):
Spoiler: show

Code: Select all

/* LCDDisplay 
 16 character 2 line I2C Display
 Backpack Interface labelled "A0 A1 A2" at lower right.
 ..and
 Backpack Interface labelled "YwRobot Arduino LCM1602 IIC V1"
 MOST use address 0x27, a FEW use 0x3F
*/ 

// Enable debug prints to serial monitor
#define MY_DEBUG 

// Enable and select radio type attached
#define MY_RADIO_NRF24
//#define MY_RADIO_RFM69

#define MY_NODE_ID 254

#include <SPI.h>
#include <MySensor.h> 
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

#define CHILD_ID 1                              // Id of the sensor child 
unsigned long POLL_FREQUENCY_TEMP = 30000;           // Minimum time between send (in milliseconds). We don't want to spam the gateway.
unsigned long POLL_FREQUENCY_POWER = 10000;
unsigned long POLL_FREQUENCY_GAS = 62000;
unsigned long POLL_FREQUENCY_WATER = 40000;
MyMessage pollRequestMsg(CHILD_ID,V_CUSTOM);

#define ID_TEMP_HUM_SENSOR_OUTSIDE 1771
#define ID_POWER_METER 1768
#define ID_GAS_METER 1773
#define ID_WATER_METER 2531

// set the LCD address to 0x27 for a 16 chars 2 line display
// A FEW use address 0x3F
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address
#define LCD_WIDTH 16
#define LCD_HEIGHT 2

// Creat a set of new characters
byte cdegrees[8] = {
  0b01100,
  0b10010,
  0b10010,
  0b01100,
  0b00000,
  0b00000,
  0b00000,
  0b00000
};

unsigned long lastTempPolled=0;
unsigned long lastPowerPolled=0;
unsigned long lastGasPolled=0;
unsigned long lastWaterPolled=0;
String LastPowerUsage;
String LastGasUsage;
String lastTemp;
String lastHum;
String lastWater;
bool tempReceived=false;
bool powerReceived=false;
bool gasReceived=false;
bool waterReceived=false;

void CenterString(String &inText, const int width)
{
  int osize=inText.length();
  if (osize>=width)
    return;
  int padLeft=(width-osize)/2;
  for (int ii=0; ii<padLeft; ii++)
  {
    inText=" " + inText;
  }
  while (inText.length()<width)
  {
    inText=inText+" ";
  }
}

String SpaceStrings(const String &lString, const String &rString)
{
  String lText=lString;
  int ibc = LCD_WIDTH - lText.length() - rString.length();
  while (ibc>0) {
    lText+=" ";
    ibc--;
  }
  lText+=rString;
  return lText;
}

void setup()
{
  LastPowerUsage="-";
  LastGasUsage="-";
  lastTemp="-";
  lastHum="-";
  lastWater="-";

  lcd.begin(LCD_WIDTH,LCD_HEIGHT);   // initialize the lcd for 16 chars 2 lines, turn on backlight
  
  lcd.createChar (1, cdegrees);    // load character to the LCD
  
  lcd.backlight();

  lcd.home ();                   // go home

  String sText;
  sText="LCD Display  1.0";
  CenterString(sText, LCD_WIDTH);
  lcd.print(sText);
  lcd.setCursor ( 0, 1 );        // go to the next line
  sText="(c)2015 GizMoCuz";
  CenterString(sText, LCD_WIDTH);
  lcd.print(sText);
  wait(1000);
}

void presentation()  {
  // Send the sketch version information to the gateway and Controller
  sendSketchInfo("LCD Display", "1.0");
}

void loop()
{
  unsigned long currentTime = millis();
  if ((!tempReceived)||((currentTime - lastTempPolled > POLL_FREQUENCY_TEMP)))
  {
    lastTempPolled = currentTime;
    //Request the temperature sensor
    send(pollRequestMsg.set(ID_TEMP_HUM_SENSOR_OUTSIDE));
    wait(500);
  }
  if ((!powerReceived)||((currentTime - lastPowerPolled > POLL_FREQUENCY_POWER)))
  {
    lastPowerPolled = currentTime;
    //Request the Power sensor
    send(pollRequestMsg.set(ID_POWER_METER));
    wait(500);
  }
  if ((!gasReceived)||((currentTime - lastGasPolled > POLL_FREQUENCY_GAS)))
  {
    lastGasPolled = currentTime;
    //Request the Gas sensor
    send(pollRequestMsg.set(ID_GAS_METER));
    wait(500);
  }
  if ((!waterReceived)||((currentTime - lastWaterPolled > POLL_FREQUENCY_WATER)))
  {
    lastWaterPolled = currentTime;
    //Request the Water sensor
    send(pollRequestMsg.set(ID_WATER_METER));
    wait(500);
  }
  wait(5000);
}

void PrintTempHumWater()
{
  lcd.setCursor ( 0, 0 );
  String lText,rText;
  lText=lastTemp;
  lText+=char(1);
  lText+="/";
  lText+=lastHum;
  lText+="%";
  
  rText=lastWater;
  rText+=" L";
  String outString=SpaceStrings(lText,rText);
  lcd.print(outString);
}

void PrintPowerGasUsage()
{
  lcd.setCursor ( 0, 1 );
  String PText,GText;
  PText=LastPowerUsage;
  PText+=" W";
  
  GText=LastGasUsage;
  GText+=" m3";

  String outString=SpaceStrings(PText,GText);
  lcd.print(outString);
}

String getValue(String data, char separator, int index)
{
  int found = 0;
  int strIndex[] = {0, -1  };
  int maxIndex = data.length()-1;
  for(int i=0; i<=maxIndex && found<=index; i++){
    if(data.charAt(i)==separator || i==maxIndex){
      found++;
      strIndex[0] = strIndex[1]+1;
      strIndex[1] = (i == maxIndex) ? i+1 : i;
    }
  }
  return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
}

void receive(const MyMessage &message) {
  if (message.type==V_CUSTOM) {
    String cMessage =  message.getString();
    int idx = getValue(cMessage, '#', 0).toInt();
    if (idx == ID_TEMP_HUM_SENSOR_OUTSIDE) {
      //0,temp,hum,humstatus
      tempReceived=true;
      lastTemp=getValue(cMessage, '#', 2);
      lastHum=getValue(cMessage, '#', 3);
      PrintTempHumWater();
    }
    else if (idx == ID_POWER_METER) {
      //0,power usage
      powerReceived=true;
      LastPowerUsage = getValue(cMessage, '#', 2);
      PrintPowerGasUsage();
    }
    else if (idx == ID_GAS_METER) {
      //0,gas usage
      gasReceived=true;
      LastGasUsage = getValue(cMessage, '#', 2);
      PrintPowerGasUsage();
    }
    else if (idx == ID_WATER_METER) {
      //0,water usage
      waterReceived=true;
      lastWater = getValue(cMessage, '#', 2);
      PrintTempHumWater();
    }
    else {
      Serial.print("Received unknown custom message from gw:");
      Serial.println(cMessage);
    }
  }
}
You need Domoticz #3560 or higher
Quality outlives Quantity!
toreandre
Posts: 91
Joined: Tuesday 19 January 2016 12:51
Target OS: -
Domoticz version:
Contact:

Re: New value type V_CUSTOM and example

Post by toreandre »

gizmocuz wrote:There is a new value type in MySensors (1.6 development branch) that can be used for various things.
For Domoticz the implementation is that you can request a sensor value (nValue/sValue) from Domoticz.

As an example i created a LCD sketch (16x2) that displays the outside temperature, the water/gas and power meter values:

MySensorsVCustom.PNG

Here is the sketch (a quick hack):
Spoiler: show

Code: Select all

/* LCDDisplay 
 16 character 2 line I2C Display
 Backpack Interface labelled "A0 A1 A2" at lower right.
 ..and
 Backpack Interface labelled "YwRobot Arduino LCM1602 IIC V1"
 MOST use address 0x27, a FEW use 0x3F
*/ 

// Enable debug prints to serial monitor
#define MY_DEBUG 

// Enable and select radio type attached
#define MY_RADIO_NRF24
//#define MY_RADIO_RFM69

#define MY_NODE_ID 254

#include <SPI.h>
#include <MySensor.h> 
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

#define CHILD_ID 1                              // Id of the sensor child 
unsigned long POLL_FREQUENCY_TEMP = 30000;           // Minimum time between send (in milliseconds). We don't want to spam the gateway.
unsigned long POLL_FREQUENCY_POWER = 10000;
unsigned long POLL_FREQUENCY_GAS = 62000;
unsigned long POLL_FREQUENCY_WATER = 40000;
MyMessage pollRequestMsg(CHILD_ID,V_CUSTOM);

#define ID_TEMP_HUM_SENSOR_OUTSIDE 1771
#define ID_POWER_METER 1768
#define ID_GAS_METER 1773
#define ID_WATER_METER 2531

// set the LCD address to 0x27 for a 16 chars 2 line display
// A FEW use address 0x3F
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address
#define LCD_WIDTH 16
#define LCD_HEIGHT 2

// Creat a set of new characters
byte cdegrees[8] = {
  0b01100,
  0b10010,
  0b10010,
  0b01100,
  0b00000,
  0b00000,
  0b00000,
  0b00000
};

unsigned long lastTempPolled=0;
unsigned long lastPowerPolled=0;
unsigned long lastGasPolled=0;
unsigned long lastWaterPolled=0;
String LastPowerUsage;
String LastGasUsage;
String lastTemp;
String lastHum;
String lastWater;
bool tempReceived=false;
bool powerReceived=false;
bool gasReceived=false;
bool waterReceived=false;

void CenterString(String &inText, const int width)
{
  int osize=inText.length();
  if (osize>=width)
    return;
  int padLeft=(width-osize)/2;
  for (int ii=0; ii<padLeft; ii++)
  {
    inText=" " + inText;
  }
  while (inText.length()<width)
  {
    inText=inText+" ";
  }
}

String SpaceStrings(const String &lString, const String &rString)
{
  String lText=lString;
  int ibc = LCD_WIDTH - lText.length() - rString.length();
  while (ibc>0) {
    lText+=" ";
    ibc--;
  }
  lText+=rString;
  return lText;
}

void setup()
{
  LastPowerUsage="-";
  LastGasUsage="-";
  lastTemp="-";
  lastHum="-";
  lastWater="-";

  lcd.begin(LCD_WIDTH,LCD_HEIGHT);   // initialize the lcd for 16 chars 2 lines, turn on backlight
  
  lcd.createChar (1, cdegrees);    // load character to the LCD
  
  lcd.backlight();

  lcd.home ();                   // go home

  String sText;
  sText="LCD Display  1.0";
  CenterString(sText, LCD_WIDTH);
  lcd.print(sText);
  lcd.setCursor ( 0, 1 );        // go to the next line
  sText="(c)2015 GizMoCuz";
  CenterString(sText, LCD_WIDTH);
  lcd.print(sText);
  wait(1000);
}

void presentation()  {
  // Send the sketch version information to the gateway and Controller
  sendSketchInfo("LCD Display", "1.0");
}

void loop()
{
  unsigned long currentTime = millis();
  if ((!tempReceived)||((currentTime - lastTempPolled > POLL_FREQUENCY_TEMP)))
  {
    lastTempPolled = currentTime;
    //Request the temperature sensor
    send(pollRequestMsg.set(ID_TEMP_HUM_SENSOR_OUTSIDE));
    wait(500);
  }
  if ((!powerReceived)||((currentTime - lastPowerPolled > POLL_FREQUENCY_POWER)))
  {
    lastPowerPolled = currentTime;
    //Request the Power sensor
    send(pollRequestMsg.set(ID_POWER_METER));
    wait(500);
  }
  if ((!gasReceived)||((currentTime - lastGasPolled > POLL_FREQUENCY_GAS)))
  {
    lastGasPolled = currentTime;
    //Request the Gas sensor
    send(pollRequestMsg.set(ID_GAS_METER));
    wait(500);
  }
  if ((!waterReceived)||((currentTime - lastWaterPolled > POLL_FREQUENCY_WATER)))
  {
    lastWaterPolled = currentTime;
    //Request the Water sensor
    send(pollRequestMsg.set(ID_WATER_METER));
    wait(500);
  }
  wait(5000);
}

void PrintTempHumWater()
{
  lcd.setCursor ( 0, 0 );
  String lText,rText;
  lText=lastTemp;
  lText+=char(1);
  lText+="/";
  lText+=lastHum;
  lText+="%";
  
  rText=lastWater;
  rText+=" L";
  String outString=SpaceStrings(lText,rText);
  lcd.print(outString);
}

void PrintPowerGasUsage()
{
  lcd.setCursor ( 0, 1 );
  String PText,GText;
  PText=LastPowerUsage;
  PText+=" W";
  
  GText=LastGasUsage;
  GText+=" m3";

  String outString=SpaceStrings(PText,GText);
  lcd.print(outString);
}

String getValue(String data, char separator, int index)
{
  int found = 0;
  int strIndex[] = {0, -1  };
  int maxIndex = data.length()-1;
  for(int i=0; i<=maxIndex && found<=index; i++){
    if(data.charAt(i)==separator || i==maxIndex){
      found++;
      strIndex[0] = strIndex[1]+1;
      strIndex[1] = (i == maxIndex) ? i+1 : i;
    }
  }
  return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
}

void receive(const MyMessage &message) {
  if (message.type==V_CUSTOM) {
    String cMessage =  message.getString();
    int idx = getValue(cMessage, '#', 0).toInt();
    if (idx == ID_TEMP_HUM_SENSOR_OUTSIDE) {
      //0,temp,hum,humstatus
      tempReceived=true;
      lastTemp=getValue(cMessage, '#', 2);
      lastHum=getValue(cMessage, '#', 3);
      PrintTempHumWater();
    }
    else if (idx == ID_POWER_METER) {
      //0,power usage
      powerReceived=true;
      LastPowerUsage = getValue(cMessage, '#', 2);
      PrintPowerGasUsage();
    }
    else if (idx == ID_GAS_METER) {
      //0,gas usage
      gasReceived=true;
      LastGasUsage = getValue(cMessage, '#', 2);
      PrintPowerGasUsage();
    }
    else if (idx == ID_WATER_METER) {
      //0,water usage
      waterReceived=true;
      lastWater = getValue(cMessage, '#', 2);
      PrintTempHumWater();
    }
    else {
      Serial.print("Received unknown custom message from gw:");
      Serial.println(cMessage);
    }
  }
}
You need Domoticz #3560 or higher
This is a good one!

Just got it working, but how do you get temprature from a certain temp sensor?

I see that you use "#define ID_TEMP_HUM_SENSOR_OUTSIDE 1771", but how do i add my own tempdata from domoticz? What is the numbers at the end of the define?

Right now my LCD only displays "LCD display 1.0, (C)2015 GizMoCuz"

EDIT: Just figured out that the numbers at the end of the define is the IDX :)
User avatar
gizmocuz
Posts: 2394
Joined: Thursday 11 July 2013 18:59
Target OS: Raspberry Pi / ODroid
Domoticz version: beta
Location: Top of the world
Contact:

Re: New value type V_CUSTOM and example

Post by gizmocuz »

Yep... that means you got it working ;)
Quality outlives Quantity!
User avatar
sincze
Posts: 1300
Joined: Monday 02 June 2014 22:46
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.4
Location: Netherlands / Breda Area
Contact:

Re: New value type V_CUSTOM and example

Post by sincze »

A tnx a lot @Gizmocuz

To get it working:

- I used LCD driver from here: https://bitbucket.org/fmalpartida/new-l ... /downloads
- Used I2C address scanner from here to determine the address: https://arduino-info.wikispaces.com/LCD-Blue-I2C

Adjusted your .ino code to:

Code: Select all


LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

#define LCD_WIDTH 20							// Set the LCD Width
#define LCD_HEIGHT 4							// Set the LCD Height
And up and running now.
One slight thing was that I did not see anything on the screen... except for the backlight.
So I adjusted the pot meter ... and characters appeared.

Now trying to find out how to get the Domoticz current version into V_CUSTOM ;-)
Pass2php
LAN: RFLink, P1, OTGW, MySensors
USB: RFXCom, ZWave, Sonoff 3
MQTT: ZIgbee2MQTT,
ZWAVE: Zwave-JS-UI
WIFI: Mi-light, Tasmota, Xiaomi Shelly
Solar: Omnik, PVOutput
Video: Kodi, Harmony HUB, Chromecast
Sensors: You name it I got 1.
User avatar
sincze
Posts: 1300
Joined: Monday 02 June 2014 22:46
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.4
Location: Netherlands / Breda Area
Contact:

Re: New value type V_CUSTOM and example

Post by sincze »

gizmocuz wrote:There is a new value type in MySensors (1.6 development branch) that can be used for various things.
For Domoticz the implementation is that you can request a sensor value (nValue/sValue) from Domoticz.

As an example i created a LCD sketch (16x2) that displays the outside temperature, the water/gas and power meter values:

..

You need Domoticz #3560 or higher
A well just to show the result with 20x4 LCD.
Casing needs some improvement :D
20160916_164813-1.jpg
20160916_164813-1.jpg (95.48 KiB) Viewed 4688 times
Pass2php
LAN: RFLink, P1, OTGW, MySensors
USB: RFXCom, ZWave, Sonoff 3
MQTT: ZIgbee2MQTT,
ZWAVE: Zwave-JS-UI
WIFI: Mi-light, Tasmota, Xiaomi Shelly
Solar: Omnik, PVOutput
Video: Kodi, Harmony HUB, Chromecast
Sensors: You name it I got 1.
PierreSt
Posts: 6
Joined: Sunday 18 September 2016 8:47
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: New value type V_CUSTOM and example

Post by PierreSt »

@gizmocuz sorry to pester you regarding domoticz code but I have a question regarding the implementation of the V_CUSTOM variable. It seems that in the parseLine method, the part returning the variable from the domoticz db to the sensor is in the section of "message_type == MT_Set" where all the other type of variable are actually updating the domoticz db from sensor value. Why not having implemented this part in the "message_type == MT_Req" part?

Also, a bit OOT, if (more likely when) I have further questions regarding the code, would you prefer them as private messages or as topic on the forum?

Pierre
WiktorDIY
Posts: 1
Joined: Thursday 08 April 2021 0:17
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: New value type V_CUSTOM and example

Post by WiktorDIY »

Could you explain this to domoticz beginner? - I don't understand the code.
User avatar
waltervl
Posts: 5380
Joined: Monday 28 January 2019 18:48
Target OS: Linux
Domoticz version: 2024.7
Location: NL
Contact:

Re: New value type V_CUSTOM and example

Post by waltervl »

WiktorDIY wrote: Thursday 08 April 2021 0:20 Could you explain this to domoticz beginner? - I don't understand the code.
This is code to get sensor data out of the domoticz database and display it on a Mysensor device https://www.mysensors.org/
The code is running on a Mysensor (arduino) device, not on the Domoticz server. For more info go to https://www.mysensors.org/
Domoticz running on Udoo X86 (on Ubuntu)
Devices/plugins: ZigbeeforDomoticz (with Xiaomi, Ikea, Tuya devices), Nefit Easy, Midea Airco, Omnik Solar, Goodwe Solar
Post Reply

Who is online

Users browsing this forum: No registered users and 0 guests