Menu

Virtual Values on KNX with LinKNX

netsrac69
2010-11-25
2012-12-14
  • netsrac69

    netsrac69 - 2010-11-25

    I do have a radio controlled Thermometer which I can read from my Linux Box. I would now like to use LinKNX to simulate a KNX based thermometer.

    How can I do this? How can I define an actor with it's own address which then can be called by other EIB components?

    All I would need to know is how to create and object which does not send a request to the KNX Bus and how to define and change the value for this object.

    Thanks, Netsrac

     
  • JensH

    JensH - 2010-11-25

    Hi Netsrac, could yo please better explain what yo mean by:

    How can I define an actor with it's own address which then can be called by other EIB components

    ?

    Which "other components" do you have in mind?

    I had similar idea/request to define a virtual blind-control (=Software device) …and I have some ideas, but haven't had the time.
    https://sourceforge.net/projects/linknx/forums/forum/743669/topic/3730537

    Anyhow, if you want to have the temperature on the KNX-Bus, you could just send the temperature from your "linux" thermometer on the bus by using "groupwrite" from the bcusdk.
    I use this for 7 FS20 thermometers in my house.
    The only thing you don't get with this is the ability to "read" the temperature on demand.

    Which Thermometer do you use and how you "read" them via Linux?

    Thanks, best Regards, Jens

     
  • netsrac69

    netsrac69 - 2010-11-25

    Well…basically I was using a iPhone Visio "MonoKNXControl" which allows to request the temperature over the BUS via a groupaddress. That's actually all I would like to do :-)

    So I'm not talking about a frequent "groupwrite", I'm talking about a groupwrite after you got a request. But maybe this can be done via the Rules section. How do you format the groupwrite with the current temperature?!

    I use the EZControl XS1 and have a couple of Conrad SH555's connected, some script behind this, so that I can see the current themperature in a WLAN-Connected digital frame…quite nice :-)

    I also have other devices connected, so for example a water detector or a door opener contact which I would like to use to interact with the KNX bus - e.g. if door is locked, turn of all lights off. But this should be easy by just using a couple of groupwrite's in case you got the signal via the radio control interface.

    Netsrac

     
  • jef2000

    jef2000 - 2010-11-25

    Hi,

    I don't understand what you mean by "define an actor with it's own address which then can be called by other EIB components".
    On the KNX bus, you have basically 3 types of telegrams: read, write and response.
    The write telegram is the most used. That's the one that is sent when you push on a button.
    The read telegram is used to request the value of a knx group object. If a device receives a read telegram for one of its group objects, and the read flag is set for that object, the device will reply by sending a "response" telegram with its actual value.

    If the read/response is what monoknxcontrol uses, you just have to configure an object in linknx and set the "r" flag (the flags parameter of this object will be something like flags="crwtu" )
    Then you have to find a way to update the value of this object with the actual value read from the sensor, but this depends if the update must be done periodically or triggered by the sensor.
    If you have a script that can do the groupwrite with the new value then, the linknx object with the flag described above will store the value and send it when monoknxcontrol request it.

    Regards,

    Jean-François

     
  • netsrac69

    netsrac69 - 2010-11-26

    If the read/response is what monoknxcontrol uses, you just have to configure an object in linknx and set the "r" flag (the flags parameter of this object will be something like flags="crwtu" ) Then you have to find a way to update the value of this object with the actual value read from the sensor, but this depends if the update must be done periodically or triggered by the sensor. If you have a script that can do the groupwrite with the new value then, the linknx object with the flag described above will store the value and send it when monoknxcontrol request it.

    But here the problem starts. There is no object I can define, because it's a virtual object. You mean I should simply setup the object and add a groupswrite from my script to that specific address, so that linKNX will answer the READ command? I tried this, but a request to read this object will always send out a request on the bus by linKNX which then got no answer, as no-one is responding to this read request.

    Hmmm…not so clear for me…but maybe I'm just too stupid :-)

    Thanks, Netsrac

     
  • JensH

    JensH - 2010-11-26

    HI Netsrac,
    I Use S555TH as well (5 EUR for a radio temperature / humidy sensor was quite cheap!) , but connected via CUN from www.busware.de and FHEM as deamon. FHEM has so called "notifiers", which are triggered by receiving a new value from - whatever -  sensors.
    The notifier triggers in my case a script with 3 parameters:
    1.) the groupadress for the temperature
    2.) the address for the humidity
    3.) the values from fhem in a format:
    "2010-08-16_09:00:57 tf1_AU T: 13.6  H: 86.2"

    i.e. datetime, name of the sensor, Temperature and Humidity.

    the 3rd parameter is parsed in my script and splitted into the tempareture and humidity values.

    Sorry, I have not really a clue of writing perl - maybe there is a more simple way to do the conversion of floating point temperature into the EIB, expression. I just don't know.
    I just used what I read in the standards and did the "byte" conversion in my own dirty way.

    here is the script:
    (you could call it like (for example

    eibsend_templ.pl 9/1/5 9/1/10 "T: 13.6  H: 86.2"
    

    (of course you can remove the parser in the pl and pass the "T" and "H" as a seperate parameter directly into the "inTemp"/"inHum", but this is "my" limitation by FHEM)

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    #!/usr/bin/perl
    ################################################################
    #
    #
    use strict;
    use warnings;
    use IO::Socket;
    ##################################################
    # Variables:
    my $tsub;
    my $tdiv;
    my $tdiv2;
    my $i;
    my $msb;
    my $lsb;
    my @args;
    my $smsb;
    my $slsb;
    my $address1;
    my $address2;
    my $sValues;
    my $inTemp;
    my $inHum;
    my $bHum;
    my $sHum;
    my $exp;
    my $tman;
    ###################################################
    # Start the program
    if(int(@ARGV) != 3 ) {
      print "wrong call of test.pl\n";
      print " \n";
      }else {
      $address1 = $ARGV[0];
      $address2 = $ARGV[1];
      $sValues = $ARGV[2];
      if ($sValues =~ /T:(.*)H:(.*)/) {
    #   print "\nValues: ", $sValues, "\n\n";
    #   $sValues =~ /T:(.*)H:(.*)/;
        $inTemp = $1;
        $inHum = $2;  
      
          $tsub = ($inTemp *100);
          if (abs($tsub) > 67076000){
                #error
                $msb= 0x7F;
                $lsb= 0xFF;
          } else {
                $tdiv = abs($tsub/2048) *2;   # und dann lon2
                for ($i=0;$i<15;$i++){      #log2 (tdiv) berechnen
                     $tdiv2=$tdiv>>1;
                     if ($tdiv2 ==0){
                         last;
                     } else {
                        $tdiv=$tdiv2;
                     }
                }
                $tman=$inTemp * 100/(2**$i);
                $msb=($tman>>8) & 0x87;  # exponenten maskieren
                $msb+= ($i<<3);          # exponenten dazuholen
                if ($inTemp<0){
                   $msb |= 0x80;         #Vorzeichen setzen
                   }
                $msb &= 0xFF;            #und noch auf 8 bit fixieren
                $lsb=($tman & 0xFF);     #lsb ist ggfls schon "negativ"
                $slsb=sprintf  ' %x',$lsb;
                $smsb=sprintf  ' %x',$msb;
                @args = ("/usr/local/bin/groupwrite" ,"local:/tmp/eib", $address1, $smsb, $slsb);
                print @args,"\n";
                system(@args) == 0
                    or die "system @args failed: $?";
          }
          $bHum=$inHum *2.55;
          $bHum &= 255;
          $sHum=sprintf ' %x',$bHum;
          @args = ("/usr/local/bin/groupwrite" ,"local:/tmp/eib", $address2, $sHum); 
          print @args."\n";;       
          system(@args) == 0
            or die "system @args failed: $?";
          exit(0);
        }
    }
    

    Maybe this helps you to get the information on the bus. I use this since more than a year.
    best Regards, jens

     
  • JensH

    JensH - 2010-11-26

    PS.: for the temperature I use EIS5 / 9.xxx on the bus, the Humidity I just send with EIS6 / 5.001 - that's why the conversion in the 2nd part is simplier and haven't used the same approach.
    BR, Jens

     
  • jef2000

    jef2000 - 2010-11-27

    But here the problem starts. There is no object I can define, because it's a virtual object. You mean I should simply setup the object and add a groupswrite from my script to that specific address, so that linKNX will answer the READ command? I tried this, but a request to read this object will always send out a request on the bus by linKNX which then got no answer, as no-one is responding to this read request.

    Hi,

    Perhaps your problem comes from the fact that the object has no initial value, so when linknx wants to answer the read-request he as to request the value on the bus first (that's somehow stupid). To avoid this, you can set the initial value of the object with "init" parameter. E.g.:
    <object type="9.xxx" id="your_temperature_sensor" gad="1/2/3" flags="crwtu" init="21.5"/>

    With just the line above in your linknx config file, you should already be able to read value using monoknxcontrol using group address 1/2/3 and should see the value 21.5.

    Now the second part of the job is to "update" this value with the one read from sensor.
    For this I still don't know if you have to trigger a script periodically to get the value from sensor, or if the sensor has some kind of deamon that will itself trigger a script when temperature changes.
    If linknx has to trigger the script  periodically, perhaps you can use a LUA script. I recently made one for somebody to read sensor values on a 1-wire bus:

    <rule id="1wire-read">
      <condition type="timer" trigger="true">
        <every>1m</every>
      </condition>
      <actionlist>
        <action type="script">
        function read1wire(id, objname)
          out = io.popen("/usr/local/bin/owread -s localhost:4304 "..id);
          value = string.match(out:read("*a"), "[0-9.]+");
          out:close();
          set(objname, value);
        end;
        read1wire("28.FF9B25020000/temperature","Temp_FF9B25020000");
        </action>
      </actionlist>
    </rule>
    

    For you it could be something like:

    <rule id="temp-read">
      <condition type="timer" trigger="true">
        <every>1m</every>
      </condition>
      <actionlist>
        <action type="script">
        function readtemp(id, objname)
          out = io.popen("The shell command to read your sensor"..id);
          value = string.match(out:read("*a"), "[0-9.]+");
          out:close();
          set(objname, value);
        end;
        readtemp("your_temperature_sensor","id of sensor (will be appended to shell command above)");
        readtemp("your_temperature_sensor2","id of sensor 2 (will be appended to shell command above)");
        </action>
      </actionlist>
    </rule>
    

    But without knowing how exactly you read the sensor temperature it's difficult to make more than this.

    Jean-François

     
  • jef2000

    jef2000 - 2010-11-27

    And if you want an external script to update the value of an object, you can also use a shell command like this:
    printf '<write><object id="your_temperature_sensor" value="22.5"/></write>\4' | netcat localhost 1028

    If linknx is running on a different host or listening on a different port, please adapt accordingly.
    Be careful with single/double quote usage and don't forget the \4 at end (multiple write messages can be combined in a single printf as long as each message is ended by a \4).

    Jean-François

     
  • jef2000

    jef2000 - 2010-11-27

    Oups, a small mistake.
    "multiple write messages can be combined in a single printf " is not yet supported. It will be included in next release.

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.