Page 4 of 16

Re: MySensors - Gateway to Domoticz

Posted: Sunday 22 March 2015 15:33
by gizmocuz
ThinkPad wrote:I think i am already seeing that. Connected 'MYSController' to the Ethernet gateway i made, and i see the application constantly scrolling, only thing it displays is:

RECV REQ VAR1

Nice, looking forward to it! Let us know if we can help in any way :)
Below the new code, it also uses the eprom memory to load/save the pulsecount, which is much better then requesting this from the host software (domoticz),
in case its down for whatever reason ;)

A new beta is building at the moment (will take at least 15 minutes), please let us know if you got it working !

Code: Select all

//
// Use this sensor to measure volume and flow of your house watermeter.
// You need to set the correct pulsefactor of your meter (pulses per m3).
// The sensor starts by reading the pulse count reading from the eprom.
// Reports both volume and flow back to gateway.
//
// Unfortunately millis() won't increment when the Arduino is in 
// sleepmode. So we cannot make this sensor sleep if we also want  
// to calculate/report flow.
//

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

#define DIGITAL_INPUT_SENSOR 3                  // The digital input you attached your sensor.  (Only 2 and 3 generates interrupt!)

#define PULSE_FACTOR 1000                       // Nummber of blinks per m3 of your meter (One rotation/liter)

#define SLEEP_MODE false                        // flowvalue can only be reported when sleep mode is false.

#define MAX_FLOW 40                             // Max flow (l/min) value to report. This filters outliers.

#define CHILD_ID 1                              // Id of the sensor child

unsigned long SEND_FREQUENCY = 20000;           // Minimum time between send (in milliseconds). We don't want to spam the gateway.

#define EPROM_PULSECOUNT_1_STATE 1
#define EPROM_PULSECOUNT_2_STATE 2
#define EPROM_PULSECOUNT_3_STATE 3
#define EPROM_PULSECOUNT_4_STATE 4

MySensor gw;
MyMessage flowMsg(CHILD_ID,V_FLOW);
MyMessage volumeMsg(CHILD_ID,V_VOLUME);
 
double ppl = ((double)PULSE_FACTOR)/1000;        // Pulses per liter

volatile unsigned long pulseCount = 0;   
volatile unsigned long lastBlink = 0;
volatile double flow = 0;  
boolean pcReceived = false;
unsigned long oldPulseCount = 0;
unsigned long newBlink = 0;   
double oldflow = 0;
double volume;                     
double oldvolume;
unsigned long lastSend;
unsigned long lastPulse;
unsigned long currentTime;
boolean metric;

void setup()  
{  
  gw.begin(); 

  // Send the sketch version information to the gateway and Controller
  gw.sendSketchInfo("Water Meter", "1.1");

  // Register this device as Waterflow sensor
  gw.present(CHILD_ID, S_WATER);       

  //Retreive our last pulse count value from the eprom
  pulseCount = oldPulseCount = LoadLastPulseCount();

  lastSend = millis();

  attachInterrupt(1, onPulse, RISING);
}


void loop()     
{ 
  gw.process();
  currentTime = millis();
	
    // Only send values at a maximum frequency or woken up from sleep
  bool sendTime = (currentTime - lastSend) > SEND_FREQUENCY;
  if (SLEEP_MODE || sendTime)
  {
    lastSend=currentTime;

    if (!SLEEP_MODE && flow != oldflow) {
      oldflow = flow;

      //Serial.print("l/min:");
      //Serial.println(flow);

      // Check that we dont get unresonable large flow value. 
      // could hapen when long wraps or false interrupt triggered
      if (flow<((unsigned long)MAX_FLOW)) {
        gw.send(flowMsg.set(flow, 2));                   // Send flow value to gw
      }  
    }
  
    // No Pulse count in 2min 
    if(currentTime - lastPulse > 120000){
      flow = 0;
    } 

    // Pulse count has changed
    if (pulseCount != oldPulseCount) {
      oldPulseCount = pulseCount;
      SaveLastPulseCount(pulseCount);
      
      //Serial.print("pulsecount:");
      //Serial.println(pulseCount);

      double volume = ((double)pulseCount/((double)PULSE_FACTOR));     
      if (volume != oldvolume) {
        //Serial.print("volume:");
        //Serial.println(volume, 3);
        
        gw.send(volumeMsg.set(volume, 3));               // Send volume value to gw
        oldvolume = volume;
      } 
    }
  }
  if (SLEEP_MODE) {
    gw.sleep(SEND_FREQUENCY);
  }
}

unsigned long LoadLastPulseCount()
{
    int PCount_1=gw.loadState(EPROM_PULSECOUNT_1_STATE); 
    int PCount_2=gw.loadState(EPROM_PULSECOUNT_2_STATE); 
    int PCount_3=gw.loadState(EPROM_PULSECOUNT_3_STATE); 
    int PCount_4=gw.loadState(EPROM_PULSECOUNT_4_STATE); 

    //check if valid
    if ((PCount_1==0xFF)&&(PCount_2==0xFF)&&(PCount_3==0xFF)&&(PCount_4==0xFF))
      return 0;//never saved before
    unsigned long PulseCount=(PCount_1<<24)|(PCount_2<<16)|(PCount_3<<8)|PCount_4;
    //Serial.print("Last Pulsecount: ");
    //Serial.println(PulseCount);
    return PulseCount;
}

void SaveLastPulseCount(unsigned long PulseCount)
{
    int PCount_1=(PulseCount&0xFF000000)>>24; 
    int PCount_2=(PulseCount&0xFF0000)>>16; 
    int PCount_3=(PulseCount&0xFF00)>>8; 
    int PCount_4=PulseCount&0xFF; 

    gw.saveState(EPROM_PULSECOUNT_1_STATE, PCount_1); 
    gw.saveState(EPROM_PULSECOUNT_2_STATE, PCount_2); 
    gw.saveState(EPROM_PULSECOUNT_3_STATE, PCount_3); 
    gw.saveState(EPROM_PULSECOUNT_4_STATE, PCount_4); 
}

void onPulse()     
{
  if (!SLEEP_MODE)
  {
    unsigned long newBlink = micros();   
    unsigned long interval = newBlink-lastBlink;
    
    if (interval!=0)
    {
      lastPulse = millis();
      if (interval<500000L) {
        // Sometimes we get interrupt on RISING,  500000 = 0.5sek debounce ( max 120 l/min)
        return;   
      }
      flow = (60000000.0 /interval) / ppl;
    }
    lastBlink = newBlink;
  }
  pulseCount++; 
}

Re: MySensors - Gateway to Domoticz

Posted: Sunday 22 March 2015 15:43
by ThinkPad
That's really awesome! I just flashed your new code onto my TCRT5000 node... will try it when the beta is ready (and if i can get a solid signal of the rotating needle in my watermeter).
By the way, doesn't storing the pulsecount in EEPROM wear out the memory fast? Not sure how tough the EEPROM of the Arduino is, and how often you store this value... but something to keep in mind...

Re: MySensors - Gateway to Domoticz

Posted: Sunday 22 March 2015 15:47
by gizmocuz
ThinkPad wrote:That's really awesome! I just flashed your new code onto my TCRT5000 node... will try it when the beta is ready (and if i can get a solid signal of the rotating needle in my watermeter).
By the way, doesn't storing the pulsecount in EEPROM wear out the memory fast? Not sure how tough the EEPROM of the Arduino is, and how often you store this value... but something to keep in mind...
In your P1 Smart meter has also an eprom i suppose ? ;)
and it is only written when the pulse counter changes, and then only each 20 seconds during changing
so not many writes

It would be interesting to know if someone knows how many times you can write it...

... and there are many memory locations, at the moment only the first 4 are used, so 'when' you have a problem, shift it to the next 4 ;)

Re: MySensors - Gateway to Domoticz

Posted: Sunday 22 March 2015 15:48
by gizmocuz
Could you let me know if you get it working ? I am interested in this too ! (and i had a TCRT5000 here)
If its working, can you post a photo of your water meter (the reading part), and a photo where you placed the sensor?

Re: MySensors - Gateway to Domoticz

Posted: Sunday 22 March 2015 15:54
by ThinkPad
That's true, but the code in a smart meter is probably better optimized to not wearout the EEPROM than a random Arduino sketch i think ;)
But i will try it :)

And my setup is not an ideal example project, i live in a flat and my meter is not from the watercompany. The water usage of the whole flat is measured somewhere in the basement, and this usage is compared to the meters in each appartment. My watermeter is also very old (1986 or so). See pictures here: http://gathering.tweakers.net/forum/lis ... es/1596066
But i already found this setup: http://www.domoticz.com/forum/viewtopic ... =20#p29758 Maybe you can use that to create a measuring setup for your meter?

Re: MySensors - Gateway to Domoticz

Posted: Sunday 22 March 2015 15:57
by gizmocuz
EEProm is EEProm, and i bet that on every change it will store it's counters, and there are many ;)

Re: MySensors - Gateway to Domoticz

Posted: Sunday 22 March 2015 16:12
by ThinkPad
Your Arduino sketch is working 8-) :mrgreen: . Also a 'RFXmeter' device popped up under 'Devices' after i updated Domoticz to v2.2330. I have now connected a photodiode module to the node instead of the TCRT5000 module, and placed that on my smartmeter (which, apart from the P1-port also has a blinking LED). I am now waiting for a while to see if it updates correctly.

So i think the watermeter is good, now only the personal struggle begins to get the TCRT5000 measure the meter correctly Image.
Will try to align the sensor when the dishwasser is running or so

But good job so far! Really great that you could implement this so fast! I think this watermeter sketch you made can also be used for kWh and gas i think? Idea is the same, count the pulses and send it to Domoticz? Although the EEPROM part is maybe a bit tricky, as with the kWh-meter you will get a loooooooooooooot of pulses on a day.

Re: MySensors - Gateway to Domoticz

Posted: Sunday 22 March 2015 17:57
by gizmocuz
Just got a message that the EEPROM can have 100.000 write cycles, so this is not a good option !
Will have to rebuild domoticz/sketch to support the value/var request option

http://playground.arduino.cc/Code/EEPROM-Flash

Re: MySensors - Gateway to Domoticz

Posted: Sunday 22 March 2015 19:47
by gizmocuz
New code for the water sensor (new beta is building)

Code: Select all

//
// Use this sensor to measure volume and flow of your house watermeter.
// You need to set the correct pulsefactor of your meter (pulses per m3).
// The sensor starts by reading the pulse count reading from the eprom.
// Reports both volume and flow back to gateway.
//
// Unfortunately millis() won't increment when the Arduino is in 
// sleepmode. So we cannot make this sensor sleep if we also want  
// to calculate/report flow.
//

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

#define DIGITAL_INPUT_SENSOR 3                  // The digital input you attached your sensor.  (Only 2 and 3 generates interrupt!)
#define SENSOR_INTERRUPT DIGITAL_INPUT_SENSOR-2        // Usually the interrupt = pin -2 (on uno/nano anyway)

#define PULSE_FACTOR 1000                       // Nummber of blinks per m3 of your meter (One rotation/liter)

#define SLEEP_MODE false                        // flowvalue can only be reported when sleep mode is false.

#define MAX_FLOW 40                             // Max flow (l/min) value to report. This filters outliers.

#define CHILD_ID 1                              // Id of the sensor child

unsigned long SEND_FREQUENCY = 20000;           // Minimum time between send (in milliseconds). We don't want to spam the gateway.

unsigned long UPDATE_EEPROM_FREQUENCY = 60*600000;  //Update pulse counter to eprom (each hour)

#define EPROM_PULSECOUNT_1_STATE 1
#define EPROM_PULSECOUNT_2_STATE 2
#define EPROM_PULSECOUNT_3_STATE 3
#define EPROM_PULSECOUNT_4_STATE 4

MySensor gw;
MyMessage flowMsg(CHILD_ID,V_FLOW);
MyMessage volumeMsg(CHILD_ID,V_VOLUME);
MyMessage lastCounterMsg(CHILD_ID,V_VAR1);

double ppl = ((double)PULSE_FACTOR)/1000;        // Pulses per liter

volatile unsigned long pulseCount = 0;   
volatile unsigned long lastBlink = 0;
volatile double flow = 0;  
boolean pcReceived = false;
unsigned long oldPulseCount = 0;
unsigned long newBlink = 0;   
double oldflow = 0;
double volume;                     
double oldvolume;
unsigned long lastSend;
unsigned long lastEEpromUpdate;
unsigned long lastPulse;
boolean metric;

void setup()  
{  
  gw.begin(incomingMessage); 

  // Send the sketch version information to the gateway and Controller
  gw.sendSketchInfo("Water Meter", "1.1");

  // Register this device as Waterflow sensor
  gw.present(CHILD_ID, S_WATER);       

  //Retreive our last pulse count value from the eprom
  pulseCount = oldPulseCount = LoadLastPulseCount();

  // Fetch last known pulse count value from gw
  gw.request(CHILD_ID, V_VAR1);

  lastSend = lastEEpromUpdate = millis();

  attachInterrupt(SENSOR_INTERRUPT, onPulse, RISING);
}


void loop()     
{ 
  gw.process();
  unsigned long currentTime = millis();
	
    // Only send values at a maximum frequency or woken up from sleep
  bool sendTime = (currentTime - lastSend) > SEND_FREQUENCY;
  if (SLEEP_MODE || sendTime)
  {
    lastSend=currentTime;
    
    if (!pcReceived) {
      //Last Pulsecount not yet received from controller, request it again
      gw.request(CHILD_ID, V_VAR1);
    }

    if (!SLEEP_MODE && flow != oldflow) {
      oldflow = flow;

      Serial.print("l/min:");
      Serial.println(flow);

      // Check that we dont get unresonable large flow value. 
      // could hapen when long wraps or false interrupt triggered
      if (flow<((unsigned long)MAX_FLOW)) {
        gw.send(flowMsg.set(flow, 2));                   // Send flow value to gw
      }  
    }
  
    // No Pulse count in 2min 
    if(currentTime - lastPulse > 120000){
      flow = 0;
    } 

    // Pulse count has changed
    if (pulseCount != oldPulseCount) {
      oldPulseCount = pulseCount;
      if (currentTime - lastEEpromUpdate > UPDATE_EEPROM_FREQUENCY) {
        lastEEpromUpdate=currentTime;
        SaveLastPulseCount(pulseCount);
      }
      gw.send(lastCounterMsg.set(pulseCount));                  // Send  volumevalue to gw VAR1
      
      Serial.print("pulsecount:");
      Serial.println(pulseCount);

      double volume = ((double)pulseCount/((double)PULSE_FACTOR));     
      if (volume != oldvolume) {
        Serial.print("volume:");
        Serial.println(volume, 3);
        
        gw.send(volumeMsg.set(volume, 3));               // Send volume value to gw
        oldvolume = volume;
      } 
    }
  }
  if (SLEEP_MODE) {
    gw.sleep(SEND_FREQUENCY);
  }
}

void incomingMessage(const MyMessage &message) {
  if (message.type==V_VAR1) {
    unsigned long gwPulseCount=message.getLong();
    if (gwPulseCount>pulseCount) {
      pulseCount = oldPulseCount = gwPulseCount;
      Serial.print("Received last pulse count from gw:");
      Serial.println(pulseCount);
    }
    pcReceived = true;
  }
}

unsigned long LoadLastPulseCount()
{
    int PCount_1=gw.loadState(EPROM_PULSECOUNT_1_STATE); 
    int PCount_2=gw.loadState(EPROM_PULSECOUNT_2_STATE); 
    int PCount_3=gw.loadState(EPROM_PULSECOUNT_3_STATE); 
    int PCount_4=gw.loadState(EPROM_PULSECOUNT_4_STATE); 

    //check if valid
    if ((PCount_1==0xFF)&&(PCount_2==0xFF)&&(PCount_3==0xFF)&&(PCount_4==0xFF))
      return 0;//never saved before
    unsigned long PulseCount=(PCount_1<<24)|(PCount_2<<16)|(PCount_3<<8)|PCount_4;
    //Serial.print("Last Pulsecount: ");
    //Serial.println(PulseCount);
    return PulseCount;
}

void SaveLastPulseCount(unsigned long PulseCount)
{
    int PCount_1=(PulseCount&0xFF000000)>>24; 
    int PCount_2=(PulseCount&0xFF0000)>>16; 
    int PCount_3=(PulseCount&0xFF00)>>8; 
    int PCount_4=PulseCount&0xFF; 

    gw.saveState(EPROM_PULSECOUNT_1_STATE, PCount_1); 
    gw.saveState(EPROM_PULSECOUNT_2_STATE, PCount_2); 
    gw.saveState(EPROM_PULSECOUNT_3_STATE, PCount_3); 
    gw.saveState(EPROM_PULSECOUNT_4_STATE, PCount_4); 
}

void onPulse()     
{
  if (!SLEEP_MODE)
  {
    unsigned long newBlink = micros();   
    unsigned long interval = newBlink-lastBlink;
    
    if (interval!=0)
    {
      lastPulse = millis();
      if (interval<500000L) {
        // Sometimes we get interrupt on RISING,  500000 = 0.5sek debounce ( max 120 l/min)
        return;   
      }
      flow = (60000000.0 /interval) / ppl;
    }
    lastBlink = newBlink;
  }
  pulseCount++; 
}

MySensors - Gateway to Domoticz

Posted: Sunday 22 March 2015 19:59
by hansrune
Sorry. Should have read the sketch and your updates in MySensorsBase.* more thoroughly first ... This looks great. Thanks!
Isn't this what gw.request() is intended for in MySensors API ? Being able to fully rely on receiving a response may not always be possible, though. Anyway , being able to do a gw.request() in the sketch init is useful to enable updates of the value/settings in EEPROM. In that way, a corrected sensor value can be fed from Domoticz by means of a sketch reset.

Re: MySensors - Gateway to Domoticz

Posted: Sunday 22 March 2015 20:41
by ThinkPad
Nice, i will try the updated sketch and beta tomorrow. Will also look if i can get it attached to my watermeter this time.
Don't want to do it now, don't have any water usage now, and running the tap for half an hour while trying to adjust the sensor seems a bit of a waste for me :P Better do it tomorrow when the dishwasher / washing machine is running :p

Re: MySensors - Gateway to Domoticz

Posted: Monday 23 March 2015 9:28
by gizmocuz
bjornhallberg wrote:Any way to get the battery readings to work? I only have the voltage divider (and code) on some of my sensor nodes but it seems the data is getting mixed up when read by Domoticz? I.e. sensors are getting the battery readings of other sensors. Sensors that never report a value get a value anyway.

Fantastic to finally have MySensors and Domoticz working together btw!
I assumed then when a 'node' reports a battery level, this is for all sensors received from it.

Re: MySensors - Gateway to Domoticz

Posted: Monday 23 March 2015 9:35
by gizmocuz
BluesBro wrote:Does Domoticz support the IR-sensor?
It showes up in the log but not show up in the list of available devices.
Not at the moment, because i do not understand the example sketch.

In MySensors there is a variable called 'V_IR_RECEIVE'

But this is not used to send the IR code to the gw (domoticz) instead it is sending V_VAR1 messages, which i think does not make sense ;)

Then there is an option to send IR messages from the gw, to the node, there is a variable for this V_IR_SEND,
this is also not used in the example sketch

So not sure how to implement this.

I could implement the V_IR_SEND/V_IR_RECEIVE calls, but there has to be a standard first

Re: MySensors - Gateway to Domoticz

Posted: Monday 23 March 2015 9:47
by gizmocuz
BluesBro wrote:I found the error.
Domoticz add 1 zero on every reading. 10 lux in the arduino log is 100 in domoticz. And domoticz readings dont go higher than 1000 lux.
This is because i thought (and i could be wrong) the Lux value was send as a percentage.
0=0 lux, 100%=1000Lux

for example this sketch is using percentage (LightSensor Example):

http://www.mysensors.org/build/light

and the sketch underneath it (LightLuxSensor Example) uses the actual value

so whats the standard ? At the moment i have implemented it as percentage, if you convert your value in the range of 0-100% then it should work.

Re: MySensors - Gateway to Domoticz

Posted: Monday 23 March 2015 16:27
by ThinkPad
Just did a short try with the TCRT5000 to measure my watermeter but as i expected, it is really hard to align it. The gauges are so small.... (I am aiming at the most left one, the 0,001 one).

Also i need to create a better mounting system, now one mm makes the difference for the LED to go on/off. I saw a nice mounting system here: http://www.domoticz.com/forum/viewtopic ... 1103#p6746
made by a hose clamp around the meter and a metal L-profile.

P.S. I now know that on my module the green LED (=detection) is on the whole time, and turns off when something passes by.

Re: MySensors - Gateway to Domoticz

Posted: Monday 23 March 2015 23:04
by ThinkPad
Ok, i think i got the sensor aligned correctly now. Will let it run for a day and see if it produces some realistic values.
I can't find out how to reset the counter in Domoticz to zero... All the fiddling around has created a huuuuuge water consumption. I want to start from zero now when it is mounted.

I tried setting the value to zero with the JSON url from the wiki: http://www.domoticz.com/wiki/Domoticz_A ... 7s#Counter but i think because the value is saved in the Arduino it updates it back to the old value again.

How to start fresh??

Re: MySensors - Gateway to Domoticz

Posted: Tuesday 24 March 2015 10:14
by AWI
ThinkPad wrote:
How to start fresh??
Erase the EEPROM?

Code: Select all

/*
*
* This sketch clears user EEPROM (MySensors)
* load and run for > 20 secs
*
*/
#include <MySensor.h>  
#include <SPI.h>

void setup()  
{ 
  for (int i=0;i<256;i++) {
    gw.saveState(i, 0xff);
  }
}

void loop()      
{ 
  // Nothing to do here...
}

Re: MySensors - Gateway to Domoticz

Posted: Tuesday 24 March 2015 10:42
by AWI
gizmocuz wrote: and the sketch underneath it (LightLuxSensor Example) uses the actual value

so whats the standard ? At the moment i have implemented it as percentage, if you convert your value in the range of 0-100% then it should work.
Standard should be to report in Lux. The only % value is V_DIMMER. I have reported it in the MySensors forum.

Great to see the implementation growing.

! Update 24-3-2015 11:03, response on MySensors forum:

Agree, this is a "bug". The problem with the current V_* is that it contains no unit information. A backward compatible solution for this for the 1.6 release would be to introduce a V_LIGHT_LEVEL_LUX. Not pretty but it solves the problem without breaking anything.

Re: MySensors - Gateway to Domoticz

Posted: Tuesday 24 March 2015 10:56
by A1AD
gizmocuz wrote:Just got a message that the EEPROM can have 100.000 write cycles, so this is not a good option !
Will have to rebuild domoticz/sketch to support the value/var request option

http://playground.arduino.cc/Code/EEPROM-Flash
Just change the save to eeprom interval a bit? I am writing every 2 hours my water/elektra/gas values.

Re: MySensors - Gateway to Domoticz

Posted: Tuesday 24 March 2015 10:58
by gizmocuz
Thats an option, for the watermeter there is some new code here:

http://www.mysensors.org/build/pulse_water

It now relies on the V_VAR1, but start counting the pulses immediately, they will be added as soon at the gw sends the last value