mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-05-04 22:19:38 +00:00

git-svn-id: https://svn.fhem.de/fhem/trunk/fhem@2381 2b470e98-0d58-463d-a4d8-8e2adae1ed80
411 lines
12 KiB
Perl
411 lines
12 KiB
Perl
# $Id$
|
|
##############################################################################
|
|
#
|
|
# 11_OWDevice.pm
|
|
# Copyright by Dr. Boris Neubert
|
|
# e-mail: omega at online dot de
|
|
#
|
|
# This file is part of fhem.
|
|
#
|
|
# Fhem 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.
|
|
#
|
|
# Fhem 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.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with fhem. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
##############################################################################
|
|
|
|
|
|
package main;
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
|
|
###################################
|
|
sub
|
|
OWDevice_Initialize($)
|
|
{
|
|
my ($hash) = @_;
|
|
|
|
$hash->{GetFn} = "OWDevice_Get";
|
|
$hash->{SetFn} = "OWDevice_Set";
|
|
$hash->{DefFn} = "OWDevice_Define";
|
|
|
|
$hash->{AttrList} = "trimvalues loglevel:0,1,2,3,4,5";
|
|
}
|
|
|
|
###################################
|
|
# return array
|
|
# 1st element: interface
|
|
# 2nd element: array of getters/readings
|
|
# 3rd element: array of setters/readings
|
|
# 4th element: array of readings to be periodically updated
|
|
# the value of the first reading in getters is written to state
|
|
sub
|
|
OWDevice_GetDetails($) {
|
|
|
|
my ($hash)= @_;
|
|
my $interface= "";
|
|
my @getters= qw(address alias family id power type);
|
|
my @setters= qw(alias);
|
|
my @polls;
|
|
|
|
# below we use shift such that the potentially
|
|
# more important values get listed first and
|
|
# that the first reading in getters could be
|
|
# defined (it is shown in the STATE).
|
|
|
|
# http://owfs.sourceforge.net/family.html
|
|
my $family= substr($hash->{fhem}{address}, 0, 2);
|
|
if($family eq "10") {
|
|
# 18S20 high precision digital thermometer
|
|
unshift @getters, qw(temperature templow temphigh);
|
|
unshift @setters, qw(templow temphigh);
|
|
unshift @polls, qw(temperature);
|
|
$interface= "temperature";
|
|
} elsif($family eq "28") {
|
|
# 18B20 programmable resolution digital thermometer
|
|
unshift @getters, qw(temperature templow temphigh);
|
|
unshift @setters, qw(templow temphigh);
|
|
unshift @polls, qw(temperature);
|
|
$interface= "temperature";
|
|
} elsif($family eq "1D") {
|
|
# 2423 4k RAM with counter
|
|
unshift @getters, qw(counters.A counters.B);
|
|
unshift @setters, qw();
|
|
unshift @polls, qw(counters.A counters.B);
|
|
#$interface= "count";
|
|
} elsif($family eq "05") {
|
|
# 2405 - Addressable Switch
|
|
unshift @getters, qw(PIO);
|
|
unshift @setters, qw(PIO);
|
|
unshift @polls, qw(PIO);
|
|
#$interface= "state";
|
|
} elsif($family eq "12") {
|
|
# 2406, 2407 - Dual Addressable Switch with 1kbit Memory
|
|
unshift @getters, qw(PIO.A PIO.B);
|
|
unshift @setters, qw(PIO.A PIO.B);
|
|
unshift @polls, qw(PIO.A PIO.B);
|
|
#$interface= "state";
|
|
} elsif($family eq "3A") {
|
|
# 2413 1-Wire Dual Channel Addressable Switch
|
|
unshift @getters, qw(PIO.A PIO.B);
|
|
unshift @setters, qw(PIO.A PIO.B);
|
|
unshift @polls, qw(PIO.A PIO.B);
|
|
#$interface= "state";
|
|
} elsif($family eq "29") {
|
|
# 2408 - 1-Wire 8 Channel Addressable Switch
|
|
unshift @getters, qw(PIO.0 PIO.1 PIO.2 PIO.3 PIO.4 PIO.5 PIO.6 PIO.7);
|
|
unshift @setters, qw(PIO.0 PIO.1 PIO.2 PIO.3 PIO.4 PIO.5 PIO.6 PIO.7);
|
|
unshift @polls, qw(PIO.0 PIO.1 PIO.2 PIO.3 PIO.4 PIO.5 PIO.6 PIO.7);
|
|
#$interface= "state";
|
|
} elsif($family eq "reserved") {
|
|
# reserved for other devices
|
|
# add other devices here and post your additions als patch in
|
|
# http://forum.fhem.de/index.php?t=thread&frm_id=26&rid=10
|
|
};
|
|
# http://perl-seiten.homepage.t-online.de/html/perl_array.html
|
|
return ($interface, \@getters, \@setters, \@polls);
|
|
}
|
|
|
|
###################################
|
|
# This could be IORead in fhem, But there is none.
|
|
# Read http://forum.fhem.de/index.php?t=tree&goto=54027&rid=10#msg_54027
|
|
# to find out why.
|
|
sub
|
|
OWDevice_ReadFromServer($@)
|
|
{
|
|
my ($hash, @a) = @_;
|
|
|
|
my $dev = $hash->{NAME};
|
|
return if(IsDummy($dev) || IsIgnored($dev));
|
|
my $iohash = $hash->{IODev};
|
|
if(!$iohash ||
|
|
!$iohash->{TYPE} ||
|
|
!$modules{$iohash->{TYPE}} ||
|
|
!$modules{$iohash->{TYPE}}{ReadFn}) {
|
|
Log 5, "No I/O device or ReadFn found for $dev";
|
|
return;
|
|
}
|
|
|
|
no strict "refs";
|
|
my $ret = &{$modules{$iohash->{TYPE}}{ReadFn}}($iohash, @a);
|
|
use strict "refs";
|
|
return $ret;
|
|
}
|
|
|
|
###################################
|
|
sub
|
|
OWDevice_ReadValue($$) {
|
|
|
|
my ($hash,$reading)= @_;
|
|
|
|
my $address= $hash->{fhem}{address};
|
|
my $value= OWDevice_ReadFromServer($hash, "/$address/$reading");
|
|
if(defined($value)) {
|
|
$value= trim($value) if(AttrVal($hash,"trimvalues",1));
|
|
my @getters= @{$hash->{fhem}{getters}};
|
|
$hash->{STATE}= "$reading: $value" if($reading eq $getters[0]);
|
|
} else {
|
|
Log 3, $hash->{NAME} . ": reading $reading did not return a value";
|
|
}
|
|
|
|
return $value;
|
|
}
|
|
|
|
###################################
|
|
sub
|
|
OWDevice_WriteValue($$$) {
|
|
|
|
my ($hash,$reading,$value)= @_;
|
|
|
|
my $address= $hash->{fhem}{address};
|
|
IOWrite($hash, "/$address/$reading", $value);
|
|
return $value;
|
|
}
|
|
|
|
###################################
|
|
sub
|
|
OWDevice_UpdateValues($) {
|
|
|
|
my ($hash)= @_;
|
|
|
|
my @polls= @{$hash->{fhem}{polls}};
|
|
if($#polls>=0) {
|
|
my $address= $hash->{fhem}{address};
|
|
readingsBeginUpdate($hash);
|
|
foreach my $reading (@polls) {
|
|
my $value= OWDevice_ReadValue($hash,$reading);
|
|
readingsBulkUpdate($hash,$reading,$value);
|
|
}
|
|
readingsEndUpdate($hash,1);
|
|
}
|
|
InternalTimer(gettimeofday()+$hash->{fhem}{interval}, "OWDevice_UpdateValues", $hash, 0)
|
|
if(defined($hash->{fhem}{interval}));
|
|
|
|
}
|
|
|
|
###################################
|
|
sub
|
|
OWDevice_Get($@)
|
|
{
|
|
my ($hash, @a)= @_;
|
|
|
|
my $name= $hash->{NAME};
|
|
return "get $name needs one argument" if(int(@a) != 2);
|
|
my $cmdname= $a[1];
|
|
my @getters= @{$hash->{fhem}{getters}};
|
|
if($cmdname ~~ @getters) {
|
|
my $value= OWDevice_ReadValue($hash, $cmdname);
|
|
readingsSingleUpdate($hash,$cmdname,$value,1);
|
|
return $value;
|
|
} else {
|
|
return "Unknown argument $cmdname, choose one of " . join(" ", @getters);
|
|
}
|
|
}
|
|
|
|
#############################
|
|
sub
|
|
OWDevice_Set($@)
|
|
{
|
|
my ($hash, @a)= @_;
|
|
|
|
my $name= $hash->{NAME};
|
|
my $cmdname= $a[1];
|
|
my $value= $a[2];
|
|
my @setters= @{$hash->{fhem}{setters}};
|
|
if($cmdname ~~ @setters) {
|
|
return "set $name needs two arguments" if(int(@a) != 3);
|
|
OWDevice_WriteValue($hash,$cmdname,$value);
|
|
readingsSingleUpdate($hash,$cmdname,$value,1);
|
|
return undef;
|
|
} else {
|
|
return "Unknown argument $cmdname, choose one of " . join(" ", @setters);
|
|
}
|
|
}
|
|
|
|
#############################
|
|
sub
|
|
OWDevice_Define($$)
|
|
{
|
|
my ($hash, $def) = @_;
|
|
my @a = split("[ \t]+", $def);
|
|
|
|
return "Usage: define <name> OWDevice <address> [interval]" if($#a < 3 || $#a > 4);
|
|
my $name= $a[0];
|
|
|
|
AssignIoPort($hash);
|
|
if(defined($hash->{IODev}->{NAME})) {
|
|
Log 3, "$name: I/O device is " . $hash->{IODev}->{NAME};
|
|
} else {
|
|
Log 1, "$name: no I/O device";
|
|
}
|
|
|
|
$hash->{fhem}{address}= $a[2];
|
|
if($#a == 3) {
|
|
$hash->{fhem}{interval}= $a[3];
|
|
Log 5, "$name: polling every $a[3] seconds";
|
|
}
|
|
my ($interface, $gettersref, $settersref, $pollsref)= OWDevice_GetDetails($hash);
|
|
my @getters= @{$gettersref};
|
|
my @setters= @{$settersref};
|
|
my @polls= @{$pollsref};
|
|
if($interface ne "") {
|
|
$hash->{fhem}{interfaces}= $interface;
|
|
Log 5, "$name: interfaces: $interface";
|
|
}
|
|
$hash->{fhem}{getters}= $gettersref;
|
|
Log 5, "$name: getters: " . join(" ", @getters);
|
|
$hash->{fhem}{setters}= $settersref;
|
|
Log 5, "$name: setters: " . join(" ", @setters);
|
|
$hash->{fhem}{polls}= $pollsref;
|
|
Log 5, "$name: polls: " . join(" ", @polls);
|
|
|
|
OWDevice_UpdateValues($hash) if(defined($hash->{fhem}{interval}));
|
|
|
|
return undef;
|
|
}
|
|
###################################
|
|
|
|
1;
|
|
|
|
###################################
|
|
=pod
|
|
=begin html
|
|
|
|
<a name="OWDevice"></a>
|
|
<h3>OWDevice</h3>
|
|
<ul>
|
|
<br>
|
|
<a name="OWDevicedefine"></a>
|
|
<b>Define</b>
|
|
<ul>
|
|
<code>define <name> OWDevice <address> [<interval>]</code>
|
|
<br><br>
|
|
|
|
Defines a 1-wire device. The 1-wire device is identified by its <address>. It is
|
|
served by the most recently defined <a href="#OWServer">OWServer</a>.
|
|
<br><br>
|
|
|
|
If <interval> is given, the OWServer is polled every <interval> seconds for
|
|
a subset of readings.
|
|
<br><br>
|
|
|
|
OWDevice is a generic device. Its characteristics are retrieved at the time of the device's
|
|
definition. The available readings that you can get or set as well as those that are
|
|
regularly retrieved by polling can be seen when issuing the
|
|
<code><a href="#list">list</a> <name></code> command.
|
|
<br><br>
|
|
The following devices are currently supported:
|
|
<ul>
|
|
<li>18S20 high precision digital thermometer</li>
|
|
<li>18B20 programmable resolution digital thermometer</li>
|
|
<li>2423 4k RAM with counter</li>
|
|
<li>2413 1-Wire Dual Channel Addressable Switch</li>
|
|
<li>2405 Addressable Switch</li>
|
|
<li>2406, 2407 - Dual Addressable Switch with 1kbit Memory</li>
|
|
<li>2413 1-Wire Dual Channel Addressable Switch</li>
|
|
<li>2408 1-Wire 8 Channel Addressable Switch</li>
|
|
</ul>
|
|
<br><br>
|
|
Adding more devices is simple. Look at the code (subroutine <code>OWDevice_GetDetails</code>).
|
|
<br><br>
|
|
This module is completely unrelated to the 1-wire modules with names all in uppercase.
|
|
<br><br>
|
|
|
|
Example:
|
|
<ul>
|
|
<code>
|
|
define myOWServer localhost:4304<br><br>
|
|
get myOWServer devices<br>
|
|
10.487653020800 DS18S20<br><br>
|
|
define myT1 10.487653020800<br><br>
|
|
list myT1 10.487653020800<br>
|
|
Internals:<br>
|
|
...<br>
|
|
Readings:<br>
|
|
2012-12-22 20:30:07 temperature 23.1875<br>
|
|
Fhem:<br>
|
|
...<br>
|
|
getters:<br>
|
|
address<br>
|
|
alias<br>
|
|
family<br>
|
|
id<br>
|
|
power<br>
|
|
type<br>
|
|
temperature<br>
|
|
templow<br>
|
|
temphigh<br>
|
|
polls:<br>
|
|
temperature<br>
|
|
setters:<br>
|
|
alias<br>
|
|
templow<br>
|
|
temphigh<br>
|
|
...<br>
|
|
</code>
|
|
</ul>
|
|
<br>
|
|
</ul>
|
|
|
|
<a name="OWDeviceset"></a>
|
|
<b>Set</b>
|
|
<ul>
|
|
<code>set <name> <reading> <value></code>
|
|
<br><br>
|
|
Sets <reading> to <value> for the 1-wire device <name>. The permitted values are defined by the underlying
|
|
1-wire device type.
|
|
<br><br>
|
|
Example:
|
|
<ul>
|
|
<code>set myT1 templow 5</code><br>
|
|
</ul>
|
|
<br>
|
|
</ul>
|
|
|
|
|
|
<a name="OWDeviceget"></a>
|
|
<b>Get</b>
|
|
<ul>
|
|
<code>get <name> <reading> <value></code>
|
|
<br><br>
|
|
Gets <reading> for the 1-wire device <name>. The permitted values are defined by the underlying
|
|
1-wire device type.
|
|
<br><br>
|
|
Example:
|
|
<ul>
|
|
<code>get myT1 temperature</code><br>
|
|
</ul>
|
|
<br>
|
|
</ul>
|
|
|
|
|
|
<a name="OWDeviceattr"></a>
|
|
<b>Attributes</b>
|
|
<ul>
|
|
<li>trimvalues: removes leading and trailing whitespace from readings. Default is 1 (on).</li>
|
|
<li><a href="#loglevel">loglevel</a></li>
|
|
<li><a href="#eventMap">eventMap</a></li>
|
|
<li><a href="#event-on-update-reading">event-on-update-reading</a></li>
|
|
<li><a href="#event-on-change-reading">event-on-change-reading</a></li>
|
|
</ul>
|
|
<br><br>
|
|
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
|
|
=end html
|
|
=cut
|