Everspring ST814

Begonnen von peterb, 07 September 2013, 14:59:37

Vorheriges Thema - Nächstes Thema

peterb

Hallo Zusammen,

für den Feuchtigkeits- und Zemperatursensor von Everspring habe ich eine Erweiterung für die 10_Zwave.pm getestet, die soweit ganz gut funktioniert.

Ausgangslage:

Eine Abfrage der Werte (Zwave Klasse 31, Befehl 0x04) fürht zu zwei Telegrammen:

01 0C 00 04 00 06 06 31 05 01 22 00 E7 FF

01 0B 00 04 00 06 05 31 05 05 01 32 F1

Entscheidend sind die bold markierten Werte:

01 bzw. 05 kennzeichnen einen Temperaturwert (01) oder Feuchtigkeitswert (05)

Der nächste Wert ist eine Bitmaske:

22 = 00100010

Die ersten drei Bits (001) = 1 Nachkommastelle Genauigkeit
Die nächsten zwei Bits (00) = Celsius (01 = Fahrenheit)
Die letzten drei Bits (010) = Die Werte stehen in zwei Bytes (oder in einem Byte 001), im Falle des ersten Telgramms 00 E7, im zweiten Telegramm nur ein Byte (32).

Meine Erweiterung der 10_Zwave.pm sieht wie folgt aus, und funktioniert erst mal:

SENSOR_MULTILEVEL      => { id => '31',
   get   => { SensorMultilevel => "04" },
   parse => { "06310501(..)(....)" => 'sprintf("Temperature:%0.1f %s ", '.
                 'hex($2)/(10**int(hex($1)/32)), '.
                 'hex($1)&8 ? "F":"C")',
                "05310505(..)(..)" => 'sprintf("Humidity:%0.1f ", '.
                 'hex($2)/(10**int(hex($1)/32)))'},},

Allerdings weiß ich nicht, wie ich bei der Feuchtigkeit das Prozentzeichen in den Sprintf Ausdruck reinsetzen kann.

Außerdem kann man dummerweise am Sensor zwischen C und F umschalten, also wäre es prime, wenn man FHEM seitig im Falle eines Fahrenheit Wertes automatisch in Celsius umrechnen könnte.

Für Hinweise dankbar

Peter

rudolfkoenig

Danke fuer den Patch.

Habe die Texte etwas abgeaendert, damit zu den anderen Klassen, und zu den anderen Modulen passt: SensorMultilevel -> smStatus, Temperature->temperature, usw.

% wird als %% geschrieben, siehe "man -s 3 printf"

Die Umschaltung von F in C moechte ich erstmal so lassen: Umschaltung ist einfach, und FHEM-Code auch. Die Loesung soll nicht nach FHEM verlagert werden, wenn jemand sich beim Geraete-Fummeln nicht beherrschen kann.

Habe die Doku ergaenzt und eingecheckt.  Testen konnte ich es nicht.

peterb

Der Test war erfolgreich, funktioniert alles so wie es soll. Danke dafür!

Aber bezüglich der F C Umrechnung muss ich noch mal nachfragen. Soweit ich weiß kann man die Tasten am Gerät nicht sperren, also muss ich softwareseitig Fahrenheit Werte abfangen bzw. umrechnen. Wo würde man das am sinnvollsten machen?

Mir fällt ad hoc nur ein Cron Job auf Betriebssystemebene ein, in FHEM bin ich noch nicht so versiert ;)


Gruß

Peter

rudolfkoenig

Eine (von mir praeferierte) nicht-technische Loesung waere den Haushaltsmitgliedern zu erklaeren, den entsprechenden Knopf in Ruhe zu lassen.

Technische Loesungen haengen davon ab was man erreichen will:
- mit userReadings einen weiteren Attribut hizufuegen oder mit stateFormat den Status "richtig" setzen.
- in der .gplot Datei mit einem Ausdruck den Wert umrechnen

peterb

Tja, da ich meine Haushaltsmitglieder kenne, ist das ein eher unpraktischer Weg ;)

userReadings und stateFormat sagen mir jetzt beides nichts. Mit einem Ausdruck in der gPlot hatte ich tatsächlich auch schon geliebäugelt, habe haber nichts zum nachlesen gefunden.

Gibt es ein Beispiel auf das ich zurückgreifen könnte?


Gruß

Peter

simli

Hi,
First of all:  I apologize for posting in English, but it's been a long time since my schooldays and my German is a bit rusty...

The updated code works, but I see one or two problems with it.
- First of all it will not work on negative values. ( Just put the ST814 in the freezer for a couple of minutes, and you will see the problem ;-)
The value is in "two's complement" which means that you have to fiddle around a bit to get the real value when it is a negative number.
- Second the precision is hardcoded to one decimal. But that may not be true (I have another sensor with two decimals in temperature readings). This also makes the two's complement calculation a bit more tricky.

I have had this working for half a year by copying the code from ZWave_ParseMeter($) into my own function for "ZWave_ParseSensorMultilevel($)".  It's a bit big to copy in here as I was ambitious enough to make it show any type of sensorvalue. But the important part is like this:
 ...
 my $data = hex(substr($v3, 0, 2*$size));
  my $datalimit = 2**((8*$size)-1) - 1;
  if ($data > $datalimit) {
    my $datasize = 2**(8*$size);
    $data = $datasize - $data;
    $data = 0 - $data;
  };
  $v3 = $data/$prec;

  return "$txt:$v3 $unit";

Maybe this can get you guys started on writing some better code than I am able to cobble together !


 

peterb

Hi Simli,

I have not put my device into the fridge, so I missed this part :)

Anyway, I am not a programmer I am rather an ambitious try and error user with technical background. So I can't help you with your code. Sorry for that. But I can help testing if that helps.


All the best

Peter




simli

Hi Peter,

Usually I keep the sensor out of the fridge! But I actually tried it today. Had to check if there were something in your code (or in Perl) that took care of the two's complement without me understanding it.

I'm probably in more or less the same category as you when it comes to programming. As it is, my program works but it is kind of bolted on with lots of trial and error...

In addition to the ST814 I also have a FGBS001 (from Fibaro) which is able to read four 1-wire temperature sensors. I have one of those sensors hanging out of a window. So that is were I ran accross the problem with negative numbers. To use this sensor I also hacked around in the code for MULTI_INSTANCE (or MULTI_CHANNEL as it is called now in the code). I upgraded Fhem today to check your code, and I see that my MultiInstance code is not working with the changes that has been done there. Maybe I will have a look at it.

I have been meaning to return my findings to the community, but never got around to it before I saw your code. So my hope was that some of the experts here would see some neat way of tidying up my code...


Simen

simli

Okay, final post tonight - seems like I'm hijacking your thread, Peter...

After re-defining my Fibaro-sensor in the "new correct way" I now have the four temperature readings back without using my own code for "Multi Instance".

So, the built in support for Multi Channel is working fine!

I do however have to use my own code to make Fhem "see" the values from the Fibaro, as the current parsing does not include messages from the Fibaro.

This is an example of the output from the Fibaro:
000400050c600d030331050144000007bd   =>  19,81 C
000400050c600d040431050144000007b0   =>  19,68 C
000400050c600d050531050144000007c3   =>  19,87 C
000400050c600d060631050144ffffffe7   =>  -0.24 C

I'm calling my own function like this:
  SENSOR_MULTILEVEL        => { id => '31',
    get   => { smStatus    => "04" },
    parse => { "..3105(.*)" => 'ZWave_ParseSensorMultilevel($1)' }, },


Simen

rudolfkoenig

Zitat000400050c600d030331050144000007bd => 19,81 C
000400050c600d040431050144000007b0 => 19,68 C
000400050c600d050531050144000007c3 => 19,87 C
000400050c600d060631050144ffffffe7 => -0.24 C
Can you tell me more precisely where these lines come from?
As far as I know the byte before the 3105 specifies the length of the remaining data, which is not the case in this example.

peterb

Hi simli,

don't worry about hijacking as long as it isn't my fridge :)

O.K., back to your values. It seems to me that fibaro broke with the zwave compatability. Let's take a closer look:

0331050144000007bd the values after the 3105 are the interesting ones:

01 means we are measuring temperature

44 is a bitmask:
44 is 01000100 in bin. The first three bits (010) define a precision of two, the next two bits (00) stand for Celsius (01 would be Fahrenheit), and the last three bits telling us that the measured value is three bytes long.

In the plain zwave world the value itself is placed directly after the bitmask. But in your fibaro telegramms there are two trailing 00 hex values prior to your values. Maybe they don't want people using their devices with controller outside of the fibaro world. Just guessing...

07bd in decimal is 1981, with the given precision (2) and the unit (C) we get 19,81°C. Hurra...!

Maybe you can try to modify the parse string from "parse => { "06310501(..)(....)" => 'sprintf()" to something like that:

parse => { "06310501(..)0000(....)" => 'sprintf()

For the sake of completeness: The trailing 06 stands for a temperature device, 05 would be a humidity device. Your fibaro telegramms also mentionend a 03 and a 04. I don't know what this stands for at the moment. But try to omit the first byte for a first check.

Good luck

Peter

 

simli

Hi Peter,

I probably pulled those examples from the logfile or the Event Monitor before I had got the device properly recognized (minus the decoded temperature readings). I just had them in a text-file with my own comments from when I was investigating this half a year ago.

I agree with your ideas about the format, but you are miscalculating the number of bytes for the value. The last three bits are 100, which is 4 decimal. So the value is contained in "00 00 07 bd".
The rest is correct.

But the fun part is if you try to decode my last example: 000400050c600d060631050144ffffffe7
The value part here is "ff ff ff e7" which would normally be 4294967271, which in your calculation would be shown as 42949672,71 C ...

But you have to recognize that the leftmost bit of the four bytes is "1", which makes it a negative number. This is where the two's complement enters. You can probably find much better descriptions of this around the Internet, but what I do is just check for the leftmost byte and if necessary calculate the negative value. (max number contained in 4 bytes is 2^32 -1 = 4294967295. Calculate  4294967295 - 4294967271 = 24. Then make that minus, and divide by the precision as usual and you get -0,24 C )

The other numbers you see are the "channel numbers" in the Multi_channel cofiguration. So this is sensor nr.6.  ( nr1 and 2 are binary switch inputs, and 3,4,5 and 6 are temperature readings )


Simen



simli

Hello Rudolf,

The values are from a "Universal Binary Sensor" from Fibaro. I called it FGBS001 in a previous post, but that is probably just a tag from the store I bought it from. The correct designation seems to be FGBS321 v1.2
It has six channels, where four of them are temperature readings from 1-wire sensors.

Here are some new examples for you. Directly from Fhem this time, and not from my notes...

ZWDongle_0_RAWMSG   000400050c600d03033105014400000501
ZWDongle_0_RAWMSG   000400050c600d0404310501440000070e
ZWDongle_0_RAWMSG    000400050c600d0505310501440000004b
ZWDongle_0_RAWMSG   000400050c600d050531050144ffffffdb
ZWDongle_0_RAWMSG   000400050c600d060631050144000006b0
 
I have not really studied this, but it seems to me like the numbers before "3105" are channel numbers.

The first line is from "sensor 3" and is 12.81 C
Next comes "sensor4" at 18.06 C
Then I have two examples from "sensor 5". One at +0.75 C and the next at -0.37 C
And finally there is "sensor 6" showing 17.12 C

I have played around a bit with my code. Will make another post with that. Note that there is a bug in the description I made for Peter.


Simen

simli

Hello Peter,

you have got me playing around with Fhem again! I have been looking at my modification all weekend.

First I have to admit that my calculations above are wrong. The correct answer is -0.25.  I was using my own notes and fitted the description to that, sorry!

Your solution made me think about this in a new way. Instead of doing everything in a separate subroutine in the way that ZWave_ParseMeter does, I have now reduced my function to just calculating the value. That may make the calling of the function more understandable and logical?

 SENSOR_MULTILEVEL        => { id => '31',
    get   => { smStatus    => "04" },
    parse => { "..310501(..)(.*)" => 'ZWave_ExtractValue("temperature",            $1,$2, ("C"   , "F"               ))',
....


I have commented the code below to make it easier for others to see if I have made more errors ... ;-)
Hope this makes it more understandable than my previous post. I'm also attaching my modified 10_ZWave.pm if someone wants to test it. Note that it contains calls for many types of sensors. I have only tested temperature and humidity. The rest of the definitions have been picked up from various code I have seen, and updated today with more definitions from Google's Open ZWave.  


Simen



sub
ZWave_ExtractValue($$$@)
{
  my ($Txt,$Key,$Value,@Units) = @_;

  # $Key is expected to be one byte
  return if ($Key !~ m/^(..)$/);
  # $Value is expected to be at least one byte
  return if ($Value !~ m/^(..)*$/);
 
  # 1st three bits is precision
  # Shift left five places, then AND with mask "00000111"
  my $Precision = 10**((hex($Key) >> 5) & 0x7);

  # Next two bits defines unit of value
  # Shift left three places, then AND with mask "00000011"
  my $UnitIdx = (hex($Key) >> 3) & 0x3;
  # Fetch Unit from suplied array, or return "undef" if out of bounds
  my $Unit = ($UnitIdx > $#Units ? "undef" : $Units[$UnitIdx]);

  # Final three bits is number of bytes to use from $Value
  # No shift, but AND with mask "00000111"
  my $Size = (hex($Key) >> 0) & 0x7;
 
  # Check that $Value contains enough bytes... Silently ignore if
  # there are more than expected
  return if (length($Value) < $Size * 2);

  # Pick out the right number of bytes (should be all..)
  my $v1 = hex(substr($Value, 0, 2 * $Size));
  # Determine maximum positive value contained in $Size number of bytes
  my $v2 = 2 ** (( 8 * $Size) - 1);
  # ...and maximum value contained in $Size number of bytes
  my $v3 = 2 ** (8 * $Size);
  # If $v1 > $v2 then it is a negative number and needs decoding
  my $v4;
  if ($v1 > $v2) {
    $v4 = -($v3 - $v1);
  }
  # Otherwise use it as it is
  else {
    $v4 = $v1;
  };
  # Then divide by precision
  my $v5 = $v4 / $Precision;

  return "$Txt:$v5 $Unit";
}



peterb

Hi Simen,

I am a liitle bit busy at the moment. Hopefully I can test your code the next weekend.

All the best

Peter