Reported values got stuck sometimes

Discussion about Z-Uno product. Visit http://z-uno.z-wave.me for more details.
ondrej_bajer
Posts: 32
Joined: 17 May 2018 09:55

Reported values got stuck sometimes

Post by ondrej_bajer » 31 Jul 2018 11:29

Hi guys,

I've experienced a strange problem with reporting values. This Z-Uno is reading the 7 electric values via a serial interface and once a minute it sends unsolicited reports to the Fibaro HC2. At the same time, Fibaro is polling every 13 seconds. Works great, but from time to time some of the values got stuck (or freeze) and a steady numeric value is being shown in HC2 for hours.

Here's the example: monitoring a battery voltage, the two values should be a very close to each other. But the RED value got stuck for hours, till 7:40, where it magically started to behave normally.
reported value frozen.JPG
reported value frozen.JPG (66.25 KiB) Viewed 166 times
I found that more channels I have, the higher is the probability of the described behavior. With 3 channels, it works flawlessly. With 7 it starts to behave like described. Also, found that if I send unsolicited reports in a different order, it might help a bit.

Can you help me, please? :shock:

Code: Select all

.
.
.
ZUNO_SETUP_CHANNELS(
        ZUNO_SENSOR_MULTILEVEL(ZUNO_SENSOR_MULTILEVEL_TYPE_VOLTAGE, SENSOR_MULTILEVEL_SCALE_VOLT, SENSOR_MULTILEVEL_SIZE_FOUR_BYTES, SENSOR_MULTILEVEL_PRECISION_ONE_DECIMAL, getter1),
        ZUNO_SENSOR_MULTILEVEL(ZUNO_SENSOR_MULTILEVEL_TYPE_CURRENT, SENSOR_MULTILEVEL_SCALE_AMPERE, SENSOR_MULTILEVEL_SIZE_FOUR_BYTES, SENSOR_MULTILEVEL_PRECISION_TWO_DECIMALS, getter2),
        ZUNO_SENSOR_MULTILEVEL(ZUNO_SENSOR_MULTILEVEL_TYPE_VOLTAGE, SENSOR_MULTILEVEL_SCALE_VOLT, SENSOR_MULTILEVEL_SIZE_FOUR_BYTES, SENSOR_MULTILEVEL_PRECISION_ONE_DECIMAL, getter3),
        ZUNO_SENSOR_MULTILEVEL(ZUNO_SENSOR_MULTILEVEL_TYPE_CURRENT, SENSOR_MULTILEVEL_SCALE_AMPERE, SENSOR_MULTILEVEL_SIZE_FOUR_BYTES, SENSOR_MULTILEVEL_PRECISION_TWO_DECIMALS, getter4),
        ZUNO_SENSOR_MULTILEVEL(ZUNO_SENSOR_MULTILEVEL_TYPE_TEMPERATURE, SENSOR_MULTILEVEL_SCALE_CELSIUS, SENSOR_MULTILEVEL_SIZE_FOUR_BYTES, SENSOR_MULTILEVEL_PRECISION_ZERO_DECIMALS, getter5),
        ZUNO_SENSOR_MULTILEVEL(ZUNO_SENSOR_MULTILEVEL_TYPE_CURRENT, SENSOR_MULTILEVEL_SCALE_AMPERE, SENSOR_MULTILEVEL_SIZE_FOUR_BYTES, SENSOR_MULTILEVEL_PRECISION_ONE_DECIMAL, getter6),        
        ZUNO_SENSOR_MULTILEVEL(ZUNO_SENSOR_MULTILEVEL_TYPE_VOLTAGE, SENSOR_MULTILEVEL_SCALE_VOLT, SENSOR_MULTILEVEL_SIZE_FOUR_BYTES, SENSOR_MULTILEVEL_PRECISION_ONE_DECIMAL, getter7)
        );
.
.
.

    zunoSendReport(7);     // Send report without polling
    zunoSendReport(1);     // Send report without polling
    zunoSendReport(2);     // Send report without polling
    zunoSendReport(3);     // Send report without polling
    zunoSendReport(4);     // Send report without polling
    zunoSendReport(5);     // Send report without polling
    zunoSendReport(6);     // Send report without polling  
 .
 .
 .

ondrej_bajer
Posts: 32
Joined: 17 May 2018 09:55

Re: Reported values got stuck sometimes

Post by ondrej_bajer » 31 Jul 2018 11:37

HC2 associations.png
HC2 associations.png (11.85 KiB) Viewed 165 times

p0lyg0n1
Posts: 157
Joined: 04 Aug 2016 07:14

Re: Reported values got stuck sometimes

Post by p0lyg0n1 » 31 Jul 2018 13:03

Hi,
Looks like you overload package queue of Z-Uno. The most simple workaround is to add some delay (about 100ms-200ms) between reports. The good practice is to report values only when them change. May be you report one chanbel too frequently. By the standard the device couldn't send report for multilevel sensor frequently then one time in 30 seconds for one channel and Z-Uno has a special parameter to avoid this. You could paralyze all your Z-Wave network in case you do it this way. I need a whole code to check it in details.

ondrej_bajer
Posts: 32
Joined: 17 May 2018 09:55

Re: Reported values got stuck sometimes

Post by ondrej_bajer » 31 Jul 2018 17:04

Hi p0lyg0n1,

I have a polling set on the HC2 once per 13 seconds. On top of that, I'm sending the unsolicited reports once per minute, but for all the channels (1-7) at once. If I overload the package queue with unsolicited reports, can it have a negative effect on all the polling too?

Thanks!

Code: Select all

ZUNO_SETUP_CHANNELS(
        ZUNO_SENSOR_MULTILEVEL(ZUNO_SENSOR_MULTILEVEL_TYPE_VOLTAGE, SENSOR_MULTILEVEL_SCALE_VOLT, SENSOR_MULTILEVEL_SIZE_FOUR_BYTES, SENSOR_MULTILEVEL_PRECISION_ONE_DECIMAL, getter1),           // PV1InputVoltage
        ZUNO_SENSOR_MULTILEVEL(ZUNO_SENSOR_MULTILEVEL_TYPE_CURRENT, SENSOR_MULTILEVEL_SCALE_AMPERE, SENSOR_MULTILEVEL_SIZE_FOUR_BYTES, SENSOR_MULTILEVEL_PRECISION_TWO_DECIMALS, getter2),        // PV1InputAmps
        ZUNO_SENSOR_MULTILEVEL(ZUNO_SENSOR_MULTILEVEL_TYPE_VOLTAGE, SENSOR_MULTILEVEL_SCALE_VOLT, SENSOR_MULTILEVEL_SIZE_FOUR_BYTES, SENSOR_MULTILEVEL_PRECISION_ONE_DECIMAL, getter3),           // PV2InputVoltage
        ZUNO_SENSOR_MULTILEVEL(ZUNO_SENSOR_MULTILEVEL_TYPE_CURRENT, SENSOR_MULTILEVEL_SCALE_AMPERE, SENSOR_MULTILEVEL_SIZE_FOUR_BYTES, SENSOR_MULTILEVEL_PRECISION_TWO_DECIMALS, getter4),        // PV2InputAmps
        ZUNO_SENSOR_MULTILEVEL(ZUNO_SENSOR_MULTILEVEL_TYPE_TEMPERATURE, SENSOR_MULTILEVEL_SCALE_CELSIUS, SENSOR_MULTILEVEL_SIZE_FOUR_BYTES, SENSOR_MULTILEVEL_PRECISION_ZERO_DECIMALS, getter5),  // InnerTemperature
        ZUNO_SENSOR_MULTILEVEL(ZUNO_SENSOR_MULTILEVEL_TYPE_CURRENT, SENSOR_MULTILEVEL_SCALE_AMPERE, SENSOR_MULTILEVEL_SIZE_FOUR_BYTES, SENSOR_MULTILEVEL_PRECISION_ONE_DECIMAL, getter6),         // ChargingCurrent, pozor muze nabyvat i negativnich hodnot pri vybijeni baterie
        ZUNO_SENSOR_MULTILEVEL(ZUNO_SENSOR_MULTILEVEL_TYPE_VOLTAGE, SENSOR_MULTILEVEL_SCALE_VOLT, SENSOR_MULTILEVEL_SIZE_FOUR_BYTES, SENSOR_MULTILEVEL_PRECISION_ONE_DECIMAL, getter7)            // BatteryVoltage
);

#include "SoftwareSerial.h"
#define LED_PIN 13                 // LED pin number 13 = vestavena USER LED bile barvy
#define MAX_BUFFER 200             // Velikost bufferu pro prijem odpovedi od Invertoru. Musi pojmout vsechny znaky az do zakonceni pomoci <CR>, kterym Invertor konci kazdou odpoved
#define SERIAL_Console Serial                // Seriovy interface pro DEBUG
SoftwareSerial SERIAL_Inverter(14, 12);      // Seriovy interface pro komunikaci s Invertorem, pins 12 RX and 14 TX
char input_buffer[MAX_BUFFER];     // Buffer pro prijem odpovedi od Invertoru pres Serial. Odpoved od invertoru je zakoncena znakem <CR>
int buffer_position = 0;           // Counter pro vycitani bufferu znak po znaku
unsigned long nowmillis;           // Counter pro milisekundy od startu programu
unsigned long timer1_LED;          // Timer pro blikani LEDkou
unsigned long timer2_CMD;          // Timer pro periodicke dotazovani invertoru
unsigned long timer3_REPORT;       // Timer pro odesilani unsolicited reportu

int ledState = LOW;                // HIGH/LOW pro blikani LEDkou
int blikni = 0;                    // Pri zapisu do teto promenne provede LEDka prislusny pocet bliku

// Nize jsou hodnoty, ktere parsujeme z retezce ktery vraci invertor.
char ReturnID[7];                 // Sem si ulozime prvnich 5 bytu retezce, ktery vraci invertor.
char PV1InputVoltage[7]; 
char PV2InputVoltage[7];
char PV1InputAmps[7];
char PV2InputAmps[7];
char BatteryVoltage[7];          
char ChargingCurrent[7];         
char InnerTemperature[7];

long VAL_PV1InputVoltage = 0; 
long VAL_PV2InputVoltage = 0;
long VAL_PV1InputAmps = 0;
long VAL_PV2InputAmps = 0;
long VAL_BatteryVoltage = 0;          
long VAL_InnerTemperature = 0;
signed long VAL_ChargingCurrent = 0;         //signed long kvuli odesilani zapornych hodnot

void setup ()
  {
  SERIAL_Inverter.begin (2400);
  SERIAL_Console.begin (9600);
  pinMode(LED_PIN, OUTPUT);       // Prepnuti LED_PIN do rezimu digitalni vystup
  } // end of setup

void parse_RESPONSE ()            // Parsovani odpovedi od Invertoru na zaklade prvnich 5-ti bytu, ktere idenfikuji, jakou informaci nam menic predava. Napriklad: ^D0860500,0400,0300,0070,0800,010,+00400,2318,,,4995,0000,,,2316,,,4995,,,,028,028,000,0
{
   ReturnID[0] = input_buffer[0]; 
   ReturnID[1] = input_buffer[1]; 
   ReturnID[2] = input_buffer[2]; 
   ReturnID[3] = input_buffer[3]; 
   ReturnID[4] = input_buffer[4]; 
   ReturnID[5] = 0;

   if (strcmp(ReturnID, "^D086") == 0) {            // Return_ID pro command ^P003GS=^D086
       PV1InputVoltage[0] = input_buffer[5]; 
       PV1InputVoltage[1] = input_buffer[6]; 
       PV1InputVoltage[2] = input_buffer[7]; 
       PV1InputVoltage[3] = input_buffer[8]; 
       PV1InputVoltage[4] = 0;
       VAL_PV1InputVoltage = atoi(PV1InputVoltage);
       PV2InputVoltage[0] = input_buffer[10]; 
       PV2InputVoltage[1] = input_buffer[11]; 
       PV2InputVoltage[2] = input_buffer[12]; 
       PV2InputVoltage[3] = input_buffer[13]; 
       PV2InputVoltage[4] = 0;       
       VAL_PV2InputVoltage = atoi(PV2InputVoltage);
       PV1InputAmps[0] = input_buffer[15]; 
       PV1InputAmps[1] = input_buffer[16]; 
       PV1InputAmps[2] = input_buffer[17];
       PV1InputAmps[3] = input_buffer[18];
       PV1InputAmps[4] = 0;
       VAL_PV1InputAmps = atoi(PV1InputAmps);
       PV2InputAmps[0] = input_buffer[20]; 
       PV2InputAmps[1] = input_buffer[21]; 
       PV2InputAmps[2] = input_buffer[22]; 
       PV2InputAmps[3] = input_buffer[23]; 
       PV2InputAmps[4] = 0;    
       VAL_PV2InputAmps = atoi(PV2InputAmps);
       BatteryVoltage[0] = input_buffer[25]; 
       BatteryVoltage[1] = input_buffer[26]; 
       BatteryVoltage[2] = input_buffer[27]; 
       BatteryVoltage[3] = input_buffer[28]; 
       BatteryVoltage[4] = 0; 
       VAL_BatteryVoltage = atoi(BatteryVoltage);
       ChargingCurrent[0] = input_buffer[34]; 
       ChargingCurrent[1] = input_buffer[35]; 
       ChargingCurrent[2] = input_buffer[36]; 
       ChargingCurrent[3] = input_buffer[37]; 
       ChargingCurrent[4] = input_buffer[38]; 
       ChargingCurrent[5] = input_buffer[39]; 
       ChargingCurrent[6] = 0; 
       VAL_ChargingCurrent = atoi(ChargingCurrent);
       InnerTemperature[0] = input_buffer[75]; 
       InnerTemperature[1] = input_buffer[76]; 
       InnerTemperature[2] = input_buffer[77]; 
       InnerTemperature[3] = 0; 
       VAL_InnerTemperature = atoi(InnerTemperature);
        } 
      
      if (strcmp(ReturnID, "^D061") == 0) {   // Return_ID pro command ^P003PS=^D061
                                              // response ^D061 vyparsovat zde
       SERIAL_Console.println("Valid response for ^P003PS received.");
       }
      
      if (strcmp(ReturnID, "XXXXX") == 0) {  // Return_ID pro budouci command CCCCCC=XXXXX
                                             // response XXXXX vyparsovat zde
        } 
   
   // Vypsani hodnot vyparsovanych z bufferu
   SERIAL_Console.print("PARSED: "); SERIAL_Console.println(input_buffer);
   SERIAL_Console.print("PV1InputVoltage>"); SERIAL_Console.println(VAL_PV1InputVoltage);
   SERIAL_Console.print("PV1InputAmps>"); SERIAL_Console.println(VAL_PV1InputAmps);
   SERIAL_Console.print("PV2InputVoltage>"); SERIAL_Console.println(VAL_PV2InputVoltage);
   SERIAL_Console.print("PV2InputAmps>"); SERIAL_Console.println(VAL_PV2InputAmps);
   SERIAL_Console.print("InnerTemperature>"); SERIAL_Console.println(VAL_InnerTemperature);
   SERIAL_Console.print("ChargingCurrent>"); SERIAL_Console.println(VAL_ChargingCurrent);
   SERIAL_Console.print("BatteryVoltage>"); SERIAL_Console.println(VAL_BatteryVoltage);
}

void processIncomingByte (byte inByte)    // Tato funkce bude zavolana pokazde, kdyz na seriove rozhrani prijde novy znak
  {
  switch (inByte)
    {
    case '\r':                              // <CR> 0x0D narazili jsme na znak <CR> kterym Invertor oznamuje konec retezce
      input_buffer [buffer_position] = 0;   // Zapisujeme zakoncovaci nulu do input bufferu, tak aby se z nej stal zero_terminated_char_array
      buffer_position = 0;                  // Resetujeme counter pro vycitani obsahu bufferu zpet na pozici 0
      parse_RESPONSE();                     // Volame parsovani obsahu bufferu
      break;

    case '\n':                              // <LF> 0x0A na znak <LF> nereagujeme
      break;

    default:
      if (buffer_position < (MAX_BUFFER-1)) input_buffer [buffer_position++] = inByte; // Posun pozice v bufferu
      break;
    }  // end of switch
  } 

void loop()                                                // Hlavni smycka. Zde je mozne kontrolovat citace, ovladat LED, cist tlacitka. Pozor, nesmi se pouzivat funkce Delay, jinak by se mohl v mezicase zaplnit a prepsat hardwarovy buffer serioveho rozhrani.
  {
  while (SERIAL_Inverter.available () > 0) {               // Jsou na seriovem rozhrani data?
    processIncomingByte (SERIAL_Inverter.read ());         // Nacti znak ze serioveho rozhrani
    if (blikni < 1) blikni = 1;                            // Blikni jednou, protoze z invertoru prisel znak. Pokud uz blikas, nedelej nic ani nerus stavajici blikani.
    }
  
  nowmillis = millis();                                    // Ulozeni citace doby behu programu do promenne nowmillis pro dalsi zpracovani
  if (nowmillis - timer2_CMD >= 10000) {                       // timer2_CMD, periodicke dotazovani invertoru kazdych XXXX milisekund na stav jednotlivych hodnot
     timer2_CMD = nowmillis;
     SERIAL_Console.println("Sending ^P003GS command now."); 
     SERIAL_Inverter.print("^P003GS");                    // Posilame do Invertoru command, aby nam vratil hodnoty
     SERIAL_Inverter.print('\r');                          // <CR>
     }

 if (nowmillis - timer3_REPORT >= 60000) {                        // timer3_REPORT, periodicke odesilani Z-WAVE unsolicited reportu kazdych xxx milisekund.
    timer3_REPORT = nowmillis;
    SERIAL_Console.println("Sending unsolicited Z-WAVE reports now."); 
    zunoSendReport(7);     // Send report without polling
    zunoSendReport(1);     // Send report without polling
    zunoSendReport(2);     // Send report without polling
    zunoSendReport(3);     // Send report without polling
    zunoSendReport(4);     // Send report without polling
    zunoSendReport(5);     // Send report without polling
    zunoSendReport(6);     // Send report without polling    
    }        

 if (nowmillis - timer1_LED >= 20) {                    // timer1_LED, blikani LEDkou pomoci drzeni stavu HIGH/LOW vzdy nekolik milisekund
    timer1_LED = nowmillis;
    if (ledState == LOW && blikni > 0){
       ledState = HIGH;
       blikni = blikni - 1;                               // Odecitame 1 pri kazdem rozviceni LED
       }
    else ledState = LOW;
    digitalWrite(LED_PIN, ledState);
    }
  }                                                       // Konec hlavni smycky

// Z-WAVE Getters
  word getter1(){
    return VAL_PV1InputVoltage;
    }
  
  word getter2(){
    return VAL_PV1InputAmps;
    }
  
  word getter3(){
    return VAL_PV2InputVoltage;
    }
  
  word getter4(){
    return VAL_PV2InputAmps;
    }

  word getter5(){
    return VAL_InnerTemperature;
    }

  signed long getter6(){                    //pozor, kvuli prenosu minusovych hodnot je treba definovat jako signed long
    return VAL_ChargingCurrent;
    }

  word getter7(){
    return VAL_BatteryVoltage;
    }


michap
Posts: 312
Joined: 26 Mar 2013 10:35
Contact:

Re: Reported values got stuck sometimes

Post by michap » 31 Jul 2018 18:20

Hi,
the "freeze" of values - is it for same channels every time?
And - is it at any special time window? Maybe the connection to Z-Uno is bad while the freezing time? (any closed rollo shutter or something like this?)

Only a "stupid idea" ....;)

Michael

ondrej_bajer
Posts: 32
Joined: 17 May 2018 09:55

Re: Reported values got stuck sometimes

Post by ondrej_bajer » 31 Jul 2018 18:31

Hi Michael,

channel 7 was freezing the most. But it was when I was trying to have 10+ channels. Then I removed some of the monitored values and went to 7 channels. Still, the channel 7 was freezing sometimes. So I reordered unsolicited reports so channel 7 is being sent the first. I'm convinced it helped a bit, but it might be a fake impression.

There's not a specific time window and I have no roller shutters installed :)

Maybe that I'm overloading the network with all the polling as I have another 5 devices (mix of Z-Uno's and Fibaro's) , each being polled number of timer per minute...

michap
Posts: 312
Joined: 26 Mar 2013 10:35
Contact:

Re: Reported values got stuck sometimes

Post by michap » 31 Jul 2018 19:59

Try to send every 5 minutes an average value - and reduce the polling time - and check it .....

Michael

ondrej_bajer
Posts: 32
Joined: 17 May 2018 09:55

Re: Reported values got stuck sometimes

Post by ondrej_bajer » 01 Aug 2018 09:04

Hi guys,

I will walk through all my Z-Uno devices, extend intervals and remove zunoSendReport for all the channels except the 1st. Technically, I don't need zunoSendReport but I found that it helps HC2 to re-establish communication with a device after a power loss. In such a case, HC2 marks the device as Dead Node and stops polling it, zunoSendReport causes the device to appear active again. Therefore, sending a report for 1st channel should be sufficient. Am I right?

michap
Posts: 312
Joined: 26 Mar 2013 10:35
Contact:

Re: Reported values got stuck sometimes

Post by michap » 01 Aug 2018 09:18

Why you need polling at all?
The sensor (Z-Uno) will send the values to the HC2 - this is enough, right? In best case the sensor will send values only if a value was changed, or after any defined time (for the case that not changes). This will optimize the network traffic.

Michael

ondrej_bajer
Posts: 32
Joined: 17 May 2018 09:55

Re: Reported values got stuck sometimes

Post by ondrej_bajer » 01 Aug 2018 19:26

The nice feature of polling is, that you can change intervals on the fly, directly from the Z-Wave controller. With unsolicited reports, you have to put min/max update intervals in the code itself, so the change is not so quick and easy. Second reason was, that polling all the channels at same time and then using the values for calculations (IE: power from Volts x Amps) appeared consistent to me. Sending report on value change was not looking as a best approach, as Volts & Amps are changing on every read, resulting in reports being sent repeatedly in the shortest allowed time.

Therefore I went for polling first.

Now, with a growing number of devices in the network, and with the issues I do experience, it looks like the well defined unsolicited reports generation will be a better approach. But there are two complications associated, that I have to solve:
- I don't want to loose granularity of the values. For example, I cannot send a report only when a voltage changes by more than X volts.
- I don't want to end-up sending values periodically in the shortest allowed interval.

So, how about to send unsolicited report when:
- change is bigger than X AND a shortest possible interval has passed
OR
- timeout from the last report has been reached

Timeout has to be counted from the last report on that channel, because this will introduce a sort for randomness (otherwise it will end up like all the channels sending updates in the same second).

Is it a good idea or not?

Thanks!
Ondrej

Post Reply