2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-20 07:16:03 +00:00

added 10_OWServer.pm and 11_OWDevice.pm

git-svn-id: https://svn.fhem.de/fhem/trunk@2358 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
borisneubert 2012-12-23 16:12:51 +00:00
parent 5a8934e61f
commit 7932fe6bc1
3 changed files with 624 additions and 0 deletions

View File

@ -38,6 +38,7 @@
- feature: added support for UV sensors in TRX_LIGHT using RFXtrx433 (Willi Herzig) - feature: added support for UV sensors in TRX_LIGHT using RFXtrx433 (Willi Herzig)
- feature: added on-till and on-timer for set in TRX_LIGHT using RFXtrx433 (Willi Herzig) - feature: added on-till and on-timer for set in TRX_LIGHT using RFXtrx433 (Willi Herzig)
- feature: generate devices with hexcodes as state for unknown types in TRX_ELSE using RFXtrx433 (Willi Herzig) - feature: generate devices with hexcodes as state for unknown types in TRX_ELSE using RFXtrx433 (Willi Herzig)
- feature: new modules 10_OWServer.pm and 11_OWDevice.pm to interface with OWFS
- 2012-10-28 (5.3) - 2012-10-28 (5.3)
- feature: added functions trim, ltrim, rtrim, UntoggleDirect, - feature: added functions trim, ltrim, rtrim, UntoggleDirect,

268
fhem/FHEM/10_OWServer.pm Normal file
View File

@ -0,0 +1,268 @@
# $Id: $
################################################################
#
# Copyright notice
#
# (c) 2012 Copyright: Dr. Boris Neubert
# 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;
# this must be the latest OWNet from
# http://owfs.cvs.sourceforge.net/viewvc/owfs/owfs/module/ownet/perl5/OWNet/lib/OWNet.pm
# the version at CPAN is outdated and malfunctioning as at 2012-12-19
use OWNet;
#####################################
sub
OWServer_Initialize($)
{
my ($hash) = @_;
# Provider
$hash->{WriteFn}= "OWServer_Write";
$hash->{ReadFn} = "OWServer_Read";
$hash->{Clients}= ":OWDevice:";
# Consumer
$hash->{DefFn} = "OWServer_Define";
$hash->{UndefFn} = "OWServer_Undef";
$hash->{GetFn} = "OWServer_Get";
# $hash->{SetFn} = "OWServer_Set";
# $hash->{AttrFn} = "OWServer_Attr";
$hash->{AttrList}= "loglevel:0,1,2,3,4,5";
}
#####################################
sub
OWServer_Define($$)
{
my ($hash, $def) = @_;
my @a = split("[ \t]+", $def, 3);
my $name = $a[0];
if(@a < 3) {
my $msg = "wrong syntax for $name: define <name> OWServer <protocol>";
Log 2, $msg;
return $msg;
}
my $protocol = $a[2];
OWServer_CloseDev($hash);
$hash->{fhem}{Protocol}= $protocol;
OWServer_OpenDev($hash, $protocol);
return undef;
}
#####################################
sub
OWServer_Undef($$)
{
my ($hash, $arg) = @_;
my $name = $hash->{NAME};
foreach my $d (sort keys %defs) {
if(defined($defs{$d}) &&
defined($defs{$d}{IODev}) &&
$defs{$d}{IODev} == $hash)
{
my $lev = ($reread_active ? 4 : 2);
Log GetLogLevel($name,$lev), "deleting OWServer for $d";
delete $defs{$d}{IODev};
}
}
OWServer_CloseDev($hash);
return undef;
}
#####################################
sub
OWServer_CloseDev($)
{
my ($hash) = @_;
return unless(defined($hash->{fhem}{owserver}));
delete $hash->{fhem}{owserver};
}
########################
sub
OWServer_OpenDev($$)
{
my ($hash, $protocol) = @_;
my $name = $hash->{NAME};
Log 4, "$name: Opening connection to OWServer $protocol...";
my $owserver= OWNet->new($protocol);
if($owserver) {
Log 4, "$name: Successfully connected to $protocol.";
$hash->{fhem}{owserver}= $owserver;
DoTrigger($name, "CONNECTED") if($owserver);
}
return $owserver
}
#####################################
sub
OWServer_DoInit($)
{
my $hash = shift;
my $name = $hash->{NAME};
$hash->{STATE} = "Initialized" if(!$hash->{STATE});
return undef;
}
#####################################
sub
OWServer_Read($@)
{
my ($hash,$path)= @_;
return undef unless(defined($hash->{fhem}{owserver}));
return $hash->{fhem}{owserver}->read($path);
}
#####################################
sub
OWServer_Write($@)
{
my ($hash,$path,$value)= @_;
return undef unless(defined($hash->{fhem}{owserver}));
return $hash->{fhem}{owserver}->write($path,$value);
}
#####################################
sub
OWServer_Get($@)
{
my ($hash, @a) = @_;
my $name = $a[0];
return "$name: get needs at least one parameter" if(@a < 2);
my $cmd= $a[1];
#my $arg = ($a[2] ? $a[2] : "");
#my @args= @a; shift @args; shift @args;
my $owserver= $hash->{fhem}{owserver};
if($cmd eq "devices") {
my @dir= split(",", $owserver->dir());
my @devices= grep { m/^\/\d\d\.\d+$/ } @dir;
my $ret;
for my $device (@devices) {
$ret .= substr($device,1) . " " . $owserver->read($device . "/type") . "\n";
}
return $ret;
} else {
return "Unknown argument $cmd, choose one of devices"
}
}
#####################################
1;
=pod
=begin html
<a name="OWServer"></a>
<h3>OWServer</h3>
<ul>
<br>
<a name="OWDevicedefine"></a>
<b>Define</b>
<ul>
<code>define &lt;name&gt; OWDevice &lt;protocol&gt;</code>
<br><br>
Defines a logical OWServer device. OWServer is the server component of the
<a href="http://owfs.org">1-Wire Filesystem</a>. It serves as abstraction layer
for any 1-wire devices on a host. &lt;protocol&gt; has
format &lt;hostname&gt;:&lt;port&gt;. For details see
<a href="http://owfs.org/index.php?page=owserver_protocol">owserver documentation</a>.
<br><br>
You need <a href="http://owfs.cvs.sourceforge.net/viewvc/owfs/owfs/module/ownet/perl5/OWNet/lib/OWNet.pm">OWNet.pm from owfs.org</a>. Just drop it into your <code>FHEM</code>
folder alongside the <code>10_OWServer.pm</code> module. As at 2012-12-23 the OWNet module
on CPAN has an issue which renders it useless for remote connections.
<br><br>
The actual 1-wire devices are defined as <a href="#OWDevice">OWDevice</a> devices.
<br><br>
This module is completely unrelated to the 1-wire modules with names all in uppercase.
<br><br>
Examples:
<ul>
<code>define myLocalOWServer OWServer localhost:4304</code><br>
<code>define myRemoteOWServer OWServer raspi:4304</code><br>
</ul>
<br>
</ul>
<a name="OWServerset"></a>
<b>Set</b>
<ul>
none
</ul>
<br><br>
<a name="OWServerget"></a>
<b>Get</b>
<ul>
<code>get &lt;name&gt; devices</code>
<br><br>
Lists the addresses and types of all 1-wire devices provided by the owserver.
<br><br>
</ul>
<br><br>
<a name="OWDeviceattr"></a>
<b>Attributes</b>
<ul>
<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

355
fhem/FHEM/11_OWDevice.pm Normal file
View File

@ -0,0 +1,355 @@
# $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 "reserved") {
# reserved for other devices
};
# 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");
$value= trim($value) if(AttrVal($hash,"trimvalues",1));
my @getters= @{$hash->{fhem}{getters}};
Debug join(",", @getters);
Debug $getters[0];
$hash->{STATE}= $value if($reading eq $getters[0]);
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 &lt;name&gt; OWDevice &lt;address&gt; [&lt;interval&gt;]</code>
<br><br>
Defines a 1-wire device. The 1-wire device is identified by its &lt;address&gt;. It is
served by the most recently defined <a href="#OWServer">OWServer</a>.
<br><br>
If &lt;interval&gt; is given, the OWServer is polled every &lt;interval&gt; 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> &lt;name&gt;</code> command.
<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 &lt;name&gt; &lt;reading&gt; &lt;value&gt;</code>
<br><br>
Sets &lt;reading&gt; to &lt;value&gt; for the 1-wire device &lt;name&gt;. 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 &lt;name&gt; &lt;reading&gt; &lt;value&gt;</code>
<br><br>
Gets &lt;reading&gt; for the 1-wire device &lt;name&gt;. 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><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