| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542 |
- ########################################################################################
- #
- # OWID.pm
- #
- # FHEM module to commmunicate with general 1-Wire ID-ROMS
- #
- # Prof. Dr. Peter A. Henning
- # Norbert Truchsess
- #
- # $Id: 21_OWID.pm 15339 2017-10-29 08:14:07Z phenning $
- #
- ########################################################################################
- #
- # This programm is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation; either version 2 of the License, or
- # (at your option) any later version.
- #
- # The GNU General Public License can be found at
- # http://www.gnu.org/copyleft/gpl.html.
- # A copy is found in the textfile GPL.txt and important notices to the license
- # from the author is found in LICENSE.txt distributed with these scripts.
- #
- # This script is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- ########################################################################################
- package main;
- use vars qw{%attr %defs %modules $readingFnAttributes $init_done};
- use Time::HiRes qw(gettimeofday);
- use strict;
- use warnings;
- #add FHEM/lib to @INC if it is not already included. Should rather be in fhem.pl than here though...
- BEGIN {
- if (!grep(/FHEM\/lib$/,@INC)) {
- foreach my $inc (grep(/FHEM$/,@INC)) {
- push @INC,$inc."/lib";
- };
- };
- };
- use GPUtils qw(:all);
- use ProtoThreads;
- no warnings 'deprecated';
- sub Log3($$$);
- my $owx_version="7.01";
- #-- declare variables
- my %gets = (
- "present" => ":noArg",
- "id" => ":noArg",
- "version" => ":noArg"
- );
- my %sets = (
- "interval" => ""
- );
- my %updates = (
- "present" => ""
- );
-
- ########################################################################################
- #
- # The following subroutines are independent of the bus interface
- #
- # Prefix = OWID
- #
- ########################################################################################
- #
- # OWID_Initialize
- #
- # Parameter hash = hash of device addressed
- #
- ########################################################################################
- sub OWID_Initialize ($) {
- my ($hash) = @_;
- $hash->{DefFn} = "OWID_Define";
- $hash->{UndefFn} = "OWID_Undef";
- $hash->{GetFn} = "OWID_Get";
- $hash->{SetFn} = "OWID_Set";
- $hash->{AttrFn} = "OWID_Attr";
- $hash->{NotifyFn} = "OWID_Notify";
- $hash->{InitFn} = "OWID_Init";
- $hash->{AttrList} = "IODev do_not_notify:0,1 showtime:0,1 model interval ".
- $readingFnAttributes;
- #--make sure OWX is loaded so OWX_CRC is available if running with OWServer
- main::LoadModule("OWX");
- }
- #########################################################################################
- #
- # OWID_Define - Implements DefFn function
- #
- # Parameter hash = hash of device addressed, def = definition string
- #
- #########################################################################################
- sub OWID_Define ($$) {
- my ($hash, $def) = @_;
-
- #-- define <name> OWID <FAM_ID> <ROM_ID>
- my @a = split("[ \t][ \t]*", $def);
-
- my ($name,$interval,$model,$fam,$id,$crc,$ret);
-
- #-- default
- $name = $a[0];
- $interval = 300;
- $ret = "";
- #-- check syntax
- return "OWID: Wrong syntax, must be define <name> OWID [<model>] <id> [interval] or OWAD <fam>.<id> [interval]"
- if(int(@a) < 2 || int(@a) > 5);
-
- #-- different types of definition allowed
- my $a2 = $a[2];
- my $a3 = defined($a[3]) ? $a[3] : "";
- #-- no model, 2+12 characters
- if( $a2 =~ m/^[0-9|a-f|A-F]{2}\.[0-9|a-f|A-F]{12}$/ ) {
- $fam = substr($a[2],0,2);
- $id = substr($a[2],3);
- if(int(@a)>=4) { $interval = $a[3]; }
- if( $fam eq "01" ){
- $model = "DS2401";
- CommandAttr (undef,"$name model DS2401");
- }elsif( $fam eq "09" ){
- $model = "DS2502";
- CommandAttr (undef,"$name model DS2502");
- }else{
- $model = "unknown";
- CommandAttr (undef,"$name model unknown");
- }
- #-- model or family id, 12 characters
- } elsif( $a3 =~ m/^[0-9|a-f|A-F]{12}$/ ) {
- $id = $a[3];
- if(int(@a)>=5) { $interval = $a[4]; }
- #-- family id, 2 characters
- if( $a2 =~ m/^[0-9|a-f|A-F]{2}$/ ) {
- $fam = $a[2];
- if( $fam eq "01" ){
- $model = "DS2401";
- CommandAttr (undef,"$name model DS2401");
- }elsif( $fam eq "09" ){
- $model = "DS2502";
- CommandAttr (undef,"$name model DS2502");
- }else{
- $model = "unknown";
- CommandAttr (undef,"$name model unknown");
- }
- }else{
- $model = $a[2];
- if( $model eq "DS2401" ){
- $fam = "01";
- CommandAttr (undef,"$name model DS2401");
- }elsif( $model eq "DS2502" ){
- $fam = "09";
- CommandAttr (undef,"$name model DS2502");
- }else{
- return "OWID: Unknown 1-Wire device model $model";
- }
- }
- } else {
- return "OWID: $a[0] ID $a[2] invalid, specify a 12 or 2.12 digit value";
- }
-
- #-- determine CRC Code
- $crc = sprintf("%02X",OWX_CRC($fam.".".$id."00"));
-
- #-- Define device internals
- $hash->{ROM_ID} = "$fam.$id.$crc";
- $hash->{OW_ID} = $id;
- $hash->{OW_FAMILY} = $fam;
- $hash->{PRESENT} = 0;
- $hash->{INTERVAL} = $interval;
-
- #-- Couple to I/O device
- AssignIoPort($hash);
- if( !defined($hash->{IODev}) or !defined($hash->{IODev}->{NAME}) ){
- return "OWID: Warning, no 1-Wire I/O device found for $name.";
- } else {
- $hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0; #-- false for now
- }
- $modules{OWID}{defptr}{$id} = $hash;
- #--
- readingsSingleUpdate($hash,"state","Defined",1);
- Log3 $name,1, "OWID: Device $name defined.";
- $hash->{NOTIFYDEV} = "global";
- return OWID_Init($hash);
- }
- #########################################################################################
- #
- # OWID_Notify - Implements NotifyFn function
- #
- # Parameter hash = hash of device addressed, dev = device name
- #
- #########################################################################################
- sub OWID_Notify ($$) {
- my ($hash,$dev) = @_;
- if( grep(m/^(INITIALIZED|REREADCFG)$/, @{$dev->{CHANGED}}) ) {
- OWID_Init($hash);
- } elsif( grep(m/^SAVE$/, @{$dev->{CHANGED}}) ) {
- }
- }
- #########################################################################################
- #
- # OWID_Init - Implements InitFn function
- #
- # Parameter hash = hash of device addressed
- #
- #########################################################################################
- sub OWID_Init ($) {
- my ($hash)=@_;
- #-- Start timer for updates
- RemoveInternalTimer($hash);
- InternalTimer(gettimeofday()+30, "OWID_GetValues", $hash, 0);
- #--
- readingsSingleUpdate($hash,"state","Initialized",1);
-
- if (! (defined AttrVal($hash->{NAME},"stateFormat",undef))) {
- $main::attr{$hash->{NAME}}{"stateFormat"} = "{ReadingsVal(\$name,\"present\",0) ? \"present\" : \"not present\"}";
- }
-
- return undef;
- }
- #######################################################################################
- #
- # OWID_Attr - Set one attribute value for device
- #
- # Parameter hash = hash of device addressed
- # a = argument array
- #
- ########################################################################################
- sub OWID_Attr(@) {
- my ($do,$name,$key,$value) = @_;
-
- my $hash = $defs{$name};
- my $ret;
-
- if ( $do eq "set") {
- ARGUMENT_HANDLER: {
- #-- interval modified at runtime
- $key eq "interval" and do {
- #-- check value
- return "OWID: set $name interval must be >= 0" if(int($value) < 0);
- #-- update timer
- $hash->{INTERVAL} = int($value);
- if ($init_done) {
- RemoveInternalTimer($hash);
- InternalTimer(gettimeofday()+$hash->{INTERVAL}, "OWID_GetValues", $hash, 0);
- }
- last;
- };
- $key eq "IODev" and do {
- AssignIoPort($hash,$value);
- if( defined($hash->{IODev}) ) {
- $hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0;
- if ($init_done) {
- OWID_Init($hash);
- }
- }
- last;
- }
- }
- }
- return $ret;
- }
- ########################################################################################
- #
- # OWID_Get - Implements GetFn function
- #
- # Parameter hash = hash of device addressed, a = argument array
- #
- ########################################################################################
- sub OWID_Get($@) {
- my ($hash, @a) = @_;
-
- my $reading = $a[1];
- my $name = $hash->{NAME};
- my $model = $hash->{OW_MODEL};
- my $value = undef;
- my $ret = "";
- my $offset;
- my $factor;
- #-- check syntax
- return "OWID: Get argument is missing @a"
- if(int(@a) != 2);
-
- #-- check argument
- my $msg = "OWID: Get with unknown argument $a[1], choose one of ";
- $msg .= "$_$gets{$_} " foreach (keys%gets);
- return $msg
- if(!defined($gets{$a[1]}));
- #-- get id
- if($a[1] eq "id") {
- $value = $hash->{ROM_ID};
- return "$name.id => $value";
- }
-
- #-- get present
- if($a[1] eq "present") {
- #-- hash of the busmaster
- my $master = $hash->{IODev};
- my $interface = $master->{TYPE};
-
- #-- OWX interface
- if( $interface eq "OWX" ){
- $value = OWX_Verify($master,$name,$hash->{ROM_ID},0);
- #-- OWX_ASYNC interface
- }elsif( $interface eq "OWX_ASYNC" ){
- eval {
- OWX_ASYNC_RunToCompletion($hash,OWX_ASYNC_PT_Verify($hash));
- };
- return GP_Catch($@) if $@;
-
- #-- Unknown interface
- } else {
- return "OWID: Verification not yet implemented for interface $interface";
- }
- #-- process results
- if( $master->{ASYNCHRONOUS} ){
- return undef;
- }else{
- #-- generate an event only if presence has changed
- if( $value == 0 ){
- readingsSingleUpdate($hash,"present",0,$hash->{PRESENT});
- } else {
- readingsSingleUpdate($hash,"present",1,!$hash->{PRESENT});
- }
- $hash->{PRESENT} = $value;
- return "$name.present => $value";
- }
- }
-
- #-- get version
- if( $a[1] eq "version") {
- return "$name.version => $owx_version";
- }
- }
- ########################################################################################
- #
- # OWID_GetValues - Updates the reading from one device
- #
- # Parameter hash = hash of device addressed
- #
- ########################################################################################
- sub OWID_GetValues($) {
- my $hash = shift;
-
- my $name = $hash->{NAME};
- my $value = 0;
- my $ret = "";
- my $offset;
- my $factor;
-
- RemoveInternalTimer($hash);
- #-- auto-update for device disabled;
- return undef
- if( $hash->{INTERVAL} == 0 );
- #-- restart timer for updates
- InternalTimer(time()+$hash->{INTERVAL}, "OWID_GetValues", $hash, 0);
-
- #-- hash of the busmaster
- my $master = $hash->{IODev};
- my $interface = $master->{TYPE};
-
- #-- OWX interface
- if( $interface eq "OWX" ){
- $value = OWX_Verify($master,$name,$hash->{ROM_ID},0);
-
- #-- OWX_ASYNC interface
- }elsif( $interface eq "OWX_ASYNC" ){
- eval {
- OWX_ASYNC_RunToCompletion($hash,OWX_ASYNC_PT_Verify($hash));
- };
- return GP_Catch($@) if $@;
- }
- #-- process results
- if( $master->{ASYNCHRONOUS} ){
- return undef;
- }else{
- #-- generate an event only if presence has changed
- if( $value == 0 ){
- readingsSingleUpdate($hash,"present",0,$hash->{PRESENT});
- } else {
- readingsSingleUpdate($hash,"present",1,!$hash->{PRESENT});
- }
- $hash->{PRESENT} = $value;
- return "$name.present => $value";
- }
- }
- #######################################################################################
- #
- # OWID_Set - Set one value for device
- #
- # Parameter hash = hash of device addressed
- # a = argument array
- #
- ########################################################################################
- sub OWID_Set($@) {
- my ($hash, @a) = @_;
-
- my $key = $a[1];
- my $value = $a[2];
-
- #-- for the selector: which values are possible
- if (@a == 2){
- my $newkeys = join(" ", keys %sets);
- return $newkeys ;
- }
-
- #-- check syntax
- return "OWID: Set needs at least one parameter"
- if( int(@a)<3 );
- #-- check argument
- if( !defined($sets{$a[1]}) ){
- return "OWID: Set with unknown argument $a[1]";
- }
-
- my $name = $hash->{NAME};
-
- #-- set new timer interval
- if($key eq "interval") {
- # check value
- return "OWID: Set $name interval must be >= 0"
- if(int($value) < 0);
- # update timer
- $hash->{INTERVAL} = int($value);
- RemoveInternalTimer($hash);
- InternalTimer(gettimeofday()+$hash->{INTERVAL}, "OWID_GetValues", $hash, 0);
- return undef;
- }
- }
- ########################################################################################
- #
- # OWID_Undef - Implements UndefFn function
- #
- # Parameter hash = hash of device addressed
- #
- ########################################################################################
- sub OWID_Undef ($) {
- my ($hash) = @_;
- delete($modules{OWID}{defptr}{$hash->{OW_ID}});
- RemoveInternalTimer($hash);
- return undef;
- }
- 1;
- =pod
- =item device
- =item summary to control 1-Wire devices having only a serial number
- =begin html
- <a name="OWID"></a>
- <h3>OWID</h3>
- <p>FHEM module for 1-Wire devices that know only their unique ROM ID<br />
- <br />This 1-Wire module works with the OWX interface module or with the OWServer interface module
- Please define an <a href="#OWX">OWX</a> device or <a href="#OWServer">OWServer</a> device first. <br /></p>
- <br /><h4>Example</h4><br />
- <p>
- <code>define ROM1 OWX_ID OWCOUNT 09.CE780F000000 10</code>
- <br />
- </p><br />
- <a name="OWIDdefine"></a>
- <h4>Define</h4>
- <p>
- <code>define <name> OWID <fam> <id> [<interval>]</code> or <br/>
- <code>define <name> OWID <fam>.<id> [<interval>]</code>
- <br /><br /> Define a 1-Wire device.<br /><br />
- </p>
- <ul>
- <li>
- <code><fam></code>
- <br />2-character unique family id, see above
- </li>
- <li>
- <code><id></code>
- <br />12-character unique ROM id of the converter device without family id and CRC
- code
- </li>
- <li>
- <code><interval></code>
- <br />Interval in seconds for checking the presence of the device. The default is 300 seconds. </li>
- </ul>
- <br />
- <a name="OWIDset"></a>
- <h4>Set</h4>
- <ul>
- <li><a name="owid_interval">
- <code>set <name> interval <int></code></a><br />
- Interval in seconds for checking the presence of the device. The default is 300 seconds. </li>
- </ul>
- <br />
- <a name="OWIDget"></a>
- <h4>Get</h4>
- <ul>
- <li><a name="owid_id">
- <code>get <name> id</code></a>
- <br /> Returns the full 1-Wire device id OW_FAMILY.ROM_ID.CRC </li>
- <li><a name="owid_present">
- <code>get <name> present</code>
- </a>
- <br /> Returns 1 if this 1-Wire device is present, otherwise 0. </li>
- </ul>
- <h4>Attributes</h4>
- <ul><li><a name="owtherm_interval2">
- <code>attr <name> interval <int></code></a><br /> Measurement
- interval in seconds. The default is 300 seconds, a value of 0 disables the automatic update.</li>
- <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
- </ul>
-
- =end html
- =cut
|