mirror of
https://github.com/fhem/fhem-mirror.git
synced 2024-11-22 02:59:49 +00:00
JeeStuff von Parix
git-svn-id: https://svn.fhem.de/fhem/trunk@950 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
d6b5b35fff
commit
c03cffa773
465
fhem/contrib/JeeStuff/00_JeeLink.pm
Normal file
465
fhem/contrib/JeeStuff/00_JeeLink.pm
Normal file
@ -0,0 +1,465 @@
|
||||
################################################################################
|
||||
# FHEM-Modul see www.fhem.de
|
||||
# 00_JeeLink.pm
|
||||
# Modul to use a JeeLink with RF12DEMO as FHEM-IO-Device
|
||||
#
|
||||
# Usage: define <Name> JeeLink </dev/...> NodeID
|
||||
################################################################################
|
||||
# This program 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
################################################################################
|
||||
# Autor: Axel Rieger
|
||||
# Version: 1.0
|
||||
# Datum: 07.2011
|
||||
# Kontakt: fhem [bei] anax [punkt] info
|
||||
################################################################################
|
||||
package main;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Data::Dumper;
|
||||
use vars qw(%defs);
|
||||
use vars qw(%attr);
|
||||
use vars qw(%data);
|
||||
use vars qw(%modules);
|
||||
|
||||
sub JeeLink_Initialize($);
|
||||
sub JEE_Define($$);
|
||||
sub JEE_CloseDev($);
|
||||
sub JEE_OpenDev($$);
|
||||
sub JEE_Ready($);
|
||||
sub JEE_Read($);
|
||||
sub JEE_Set($);
|
||||
################################################################################
|
||||
sub JeeLink_Initialize($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
# Provider
|
||||
$hash->{ReadFn} = "JEE_Read";
|
||||
$hash->{ReadyFn} = "JEE_Ready";
|
||||
$hash->{SetFn} = "JEE_Set";
|
||||
$hash->{WriteFn} = "JEE_Write";
|
||||
$hash->{Clients} = ":JSN:JME:JPU";
|
||||
$hash->{WriteFn} = "JEE_Write";
|
||||
|
||||
my %mc = (
|
||||
"1:JSN" => "^JSN",
|
||||
"2:JME" => "^JME",
|
||||
"3:JPU" => "^JPU");
|
||||
$hash->{MatchList} = \%mc;
|
||||
|
||||
# Normal devices
|
||||
$hash->{DefFn} = "JEE_Define";
|
||||
$hash->{AttrList} = "do_not_notify:1,0 dummy:1,0 loglevel:0,1 ";
|
||||
return undef;
|
||||
}
|
||||
################################################################################
|
||||
sub JEE_Define($$) {
|
||||
# define JEE0001 JeeLink /dev/tty.usbserial-A600cKlS NodeID
|
||||
# defs = $a[0] <DEVICE-NAME> $a[1] DEVICE-TYPE $a[2]<Parameter-1->;
|
||||
my ($hash, $def) = @_;
|
||||
my @a = split(/\s+/, $def);
|
||||
|
||||
|
||||
|
||||
my $name = $a[0];
|
||||
my $dev = $a[2];
|
||||
my $NodeID = $a[3];
|
||||
|
||||
if($dev eq "none") {
|
||||
Log 1, "$name device is none, commands will be echoed only";
|
||||
$hash->{TYPE} = 'JeeLink';
|
||||
$hash->{STATE} = TimeNow() . " Dummy-Device";
|
||||
$attr{$name}{dummy} = 1;
|
||||
return undef;
|
||||
}
|
||||
|
||||
JEE_CloseDev($hash);
|
||||
if($NodeID == 0 || $NodeID > 26 ) {return "JeeLink: NodeID between 1 and 26";}
|
||||
Log 0, "JEE-Define: Name = $name dev=$dev";
|
||||
|
||||
$hash->{DeviceName} = $dev;
|
||||
$hash->{TYPE} = 'JeeLink';
|
||||
my $ret = JEE_OpenDev($hash, 0);
|
||||
my $msg = $NodeID . "i";
|
||||
$ret = &JEE_IOWrite($hash, $msg);
|
||||
return undef;
|
||||
}
|
||||
################################################################################
|
||||
sub JEE_Set($){
|
||||
my ($hash, @a) = @_;
|
||||
# Log 0, ("JEE-SET: " . Dumper(@_));
|
||||
my $fields .= "NodeID NetGRP Frequenz LED CollectMode SendMSG BroadcastMSG RAW";
|
||||
return "Unknown argument $a[1], choose one of ". $fields if($a[1] eq "?");
|
||||
# a[0] = DeviceName
|
||||
# a[1] = Command
|
||||
# Command
|
||||
# nodeID: <n>i set node ID (standard node ids are 1..26 or 'A'..'Z')
|
||||
# netGRP: <n>g set network group (RFM12 only allows 212)
|
||||
# freq -> <n>b set MHz band (4 = 433, 8 = 868, 9 = 915)
|
||||
# cMode -> <n>c - set collect mode (advanced 1, normally 0)
|
||||
# bCast -> t - broadcast max-size test packet, with ack
|
||||
# sendA -> ...,<nn> a - send data packet to node <nn>, with ack
|
||||
# sendS -> ...,<nn> s - send data packet to node <nn>, no ack
|
||||
# led -> <n> l - turn activity LED on PB1 on or off
|
||||
# Remote control commands:
|
||||
# <hchi>,<hclo>,<addr>,<cmd> f - FS20 command (868 MHz)
|
||||
# <addr>,<dev>,<on> k - KAKU command (433 MHz)
|
||||
# Flash storage (JeeLink v2 only):
|
||||
# d - dump all log markers
|
||||
# <sh>,<sl>,<t3>,<t2>,<t1>,<t0> r - replay from specified marker
|
||||
# 123,<bhi>,<blo> e - erase 4K block
|
||||
# 12,34 w - wipe entire flash memory
|
||||
my($name, $msg);
|
||||
$name = $a[0];
|
||||
# LogLevel
|
||||
my $ll = 0;
|
||||
if(defined($attr{$name}{loglevel})) {$ll = $attr{$name}{loglevel};}
|
||||
Log $ll,"$name/JEE-SET: " . $a[1] . " : " . $a[2];
|
||||
# @a ge 2
|
||||
# if(int(@a) ne 3) {return "JeeLink wrong Argument Count";}
|
||||
$msg = "";
|
||||
if($a[1] eq "NodeID") {
|
||||
if($a[2] == 0 || $a[2] > 26 ) {return "JeeLink: NodeID between 1 and 26";}
|
||||
$msg = $a[2] . "i";}
|
||||
if($a[1] eq "NetGRP") {
|
||||
if($a[2] == 0 || $a[2] > 255 ) {return "JeeLink: NetGroup between 1 and 255";}
|
||||
$msg = $a[2] . "g";}
|
||||
if($a[1] eq "Frequenz") {
|
||||
if($a[2] !~ m/433|868|933/) {return "JeeLink: Frquenz setting use 433, 868 or 933";}
|
||||
my $mhz;
|
||||
if($a[2] eq "433") {$msg = "4b";}
|
||||
if($a[2] eq "868") {$msg = "8b";}
|
||||
if($a[2] eq "915") {$msg = "9b";}
|
||||
# 4 = 433, 8 = 868, 9 = 915
|
||||
}
|
||||
# LED
|
||||
if($a[1] eq "LED" && lc($a[2]) eq "on") {
|
||||
$hash->{LED} = "ON";
|
||||
$msg = "1l";}
|
||||
if($a[1] eq "LED" && lc($a[2]) eq "off") {
|
||||
$hash->{LED} = "OFF";
|
||||
$msg = "0l";}
|
||||
# CollectMode On or Off
|
||||
if($a[1] eq "CollectMode" && lc($a[2]) eq "on") {
|
||||
$hash->{CollectMode} = "ON";
|
||||
$msg = "1c";}
|
||||
if($a[2] eq "CollectMode" && lc($a[2]) eq "off") {
|
||||
$hash->{CollectMode} = "OFF";
|
||||
$msg = "0c";}
|
||||
# RF12_MSG to Remote Node with NO ack
|
||||
# set <NAME> SendMSG NodeID Data
|
||||
if($a[1] eq "SendMSG") {$msg = $a[2] . "," . $a[3] . "s"};
|
||||
# RF12- BroadcastMSG
|
||||
if($a[1] eq "BroadcastMSG") {$msg = "t";}
|
||||
# RAW
|
||||
if($a[1] eq "RAW") {$msg = $a[2];}
|
||||
# Send MSG
|
||||
Log 0,"JEE-SET->WRITE: $msg";
|
||||
my $ret = &JEE_IOWrite($hash, $msg);
|
||||
return undef;
|
||||
|
||||
}
|
||||
################################################################################
|
||||
sub JEE_CloseDev($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my $dev = $hash->{DeviceName};
|
||||
|
||||
return if(!$dev);
|
||||
$hash->{USBDev}->close() ;
|
||||
delete($hash->{USBDev});
|
||||
delete($selectlist{"$name.$dev"});
|
||||
delete($readyfnlist{"$name.$dev"});
|
||||
delete($hash->{FD});
|
||||
}
|
||||
################################################################################
|
||||
sub JEE_OpenDev($$)
|
||||
{
|
||||
my ($hash, $reopen) = @_;
|
||||
my $dev = $hash->{DeviceName};
|
||||
my $name = $hash->{NAME};
|
||||
my $po;
|
||||
|
||||
$hash->{PARTIAL} = "";
|
||||
Log 3, "JeeLink opening $name device $dev"
|
||||
if(!$reopen);
|
||||
|
||||
my $baudrate;
|
||||
($dev, $baudrate) = split("@", $dev);
|
||||
$baudrate = 57600;
|
||||
|
||||
if ($^O=~/Win/) {
|
||||
require Win32::SerialPort;
|
||||
$po = new Win32::SerialPort ($dev);
|
||||
} else {
|
||||
require Device::SerialPort;
|
||||
$po = new Device::SerialPort ($dev);
|
||||
}
|
||||
|
||||
if(!$po) {
|
||||
return undef if($reopen);
|
||||
Log(3, "Can't open $dev: $!");
|
||||
$readyfnlist{"$name.$dev"} = $hash;
|
||||
$hash->{STATE} = "disconnected";
|
||||
return "";
|
||||
}
|
||||
$hash->{USBDev} = $po;
|
||||
if( $^O =~ /Win/ ) {
|
||||
$readyfnlist{"$name.$dev"} = $hash;
|
||||
} else {
|
||||
$hash->{FD} = $po->FILENO;
|
||||
delete($readyfnlist{"$name.$dev"});
|
||||
$selectlist{"$name.$dev"} = $hash;
|
||||
}
|
||||
|
||||
if($baudrate) {
|
||||
$po->reset_error();
|
||||
Log 3, "$name: Setting baudrate to $baudrate";
|
||||
$po->baudrate($baudrate);
|
||||
$po->databits(8);
|
||||
$po->parity('none');
|
||||
$po->stopbits(1);
|
||||
$po->handshake('none');
|
||||
}
|
||||
|
||||
if($reopen) {
|
||||
Log 1, "JeeLink $dev reappeared ($name)";
|
||||
} else {
|
||||
Log 3, "JeeLink device opened";
|
||||
}
|
||||
|
||||
# Set Defaults
|
||||
# CollectMode on
|
||||
my $ret = &JEE_IOWrite($hash, "1c");
|
||||
# QuietMode on
|
||||
$ret = &JEE_IOWrite($hash, "1q");
|
||||
# LED On
|
||||
$ret = &JEE_IOWrite($hash, "1l");
|
||||
# Set Frequenz to 868MHz
|
||||
$ret = &JEE_IOWrite($hash, "8b");
|
||||
|
||||
$hash->{STATE}="connected"; # Allow InitDev to set the state
|
||||
|
||||
DoTrigger($name, "CONNECTED") if($reopen);
|
||||
return "Initialized";
|
||||
}
|
||||
################################################################################
|
||||
sub JEE_Ready($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
return JEE_OpenDev($hash, 1)
|
||||
if($hash->{STATE} eq "disconnected");
|
||||
|
||||
# This is relevant for windows/USB only
|
||||
my $po = $hash->{USBDev};
|
||||
my ($BlockingFlags, $InBytes, $OutBytes, $ErrorFlags) = $po->status;
|
||||
# Get Config
|
||||
my $ret = &JEE_Write($hash, "i", undef);
|
||||
return ($InBytes>0);
|
||||
}
|
||||
################################################################################
|
||||
sub JEE_Read($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
# LogLevel
|
||||
# Default 4
|
||||
my $ll = 4;
|
||||
if(defined($attr{$name}{loglevel})) {
|
||||
$ll = $attr{$name}{loglevel};
|
||||
}
|
||||
my $buf = $hash->{USBDev}->input();
|
||||
#
|
||||
# Lets' try again: Some drivers return len(0) on the first read...
|
||||
if(defined($buf) && length($buf) == 0) {
|
||||
$buf = $hash->{USBDev}->input();
|
||||
}
|
||||
my $jeedata = $hash->{PARTIAL};
|
||||
$jeedata .= $buf;
|
||||
##############################################################################
|
||||
# Arduino/JeeLink
|
||||
# Prints data to the serial port as human-readable ASCII text followed by
|
||||
# a carriage return character (ASCII 13, or '\r') and
|
||||
# a newline character (ASCII 10, or '\n').
|
||||
# HEX 0D AD \xf0
|
||||
if($jeedata =~ m/\n$/){
|
||||
chomp($jeedata);
|
||||
chop($jeedata);
|
||||
my $status = substr($jeedata, 0, 2);
|
||||
Log $ll,("$name/JeeLink RAW:$status -> $jeedata");
|
||||
if($status =~/^OK/){
|
||||
Log $ll,("$name/JeeLink Dispatch RAW:$jeedata");
|
||||
&JEE_DispatchData($jeedata,$name,$ll);
|
||||
}
|
||||
elsif($jeedata =~ m/(^.*i)([0-9]{1,2})(\*.g)([0-9]{1,3})(.@.)([0-9]{1,3})(.MHz.*)/) {
|
||||
JEE_RF12MSG($jeedata,$name,$ll);
|
||||
}
|
||||
elsif($jeedata =~/^DF/){JEE_RF12MSG($jeedata,$name,$ll);}
|
||||
$jeedata = "";
|
||||
}
|
||||
if($jeedata =~ m/^\x0A/) {
|
||||
Log $ll,("$name/JeeLink RAW DEL HEX-0A:$jeedata -> $jeedata");
|
||||
$jeedata =~ s/\x0A//;
|
||||
}
|
||||
$hash->{PARTIAL} = $jeedata;
|
||||
}
|
||||
################################################################################
|
||||
sub JEE_DispatchData($){
|
||||
my ($rawdata,$name,$ll) = @_;
|
||||
my @data = split(/\s+/,$rawdata);
|
||||
my $status = shift(@data);
|
||||
my $NodeID = shift(@data);
|
||||
# see http://talk.jeelabs.net/topic/642#post-3622
|
||||
# The id +32 is what you see when the node requests an ACK.
|
||||
if($NodeID > 31) {$NodeID = $NodeID - 32;}
|
||||
Log $ll, "$name JEE-DISP: Status:$status NodeID:$NodeID Data:$rawdata";
|
||||
# normalize 0 => 00 without NodeID
|
||||
for(my $i=0;$i<=$#data;$i++){
|
||||
if(length($data[$i]) == 1) { $data[$i] = "0" . $data[$i]}
|
||||
}
|
||||
# SensorData to Dispatch
|
||||
my ($DispData,$SType,$SPre,@SData,$data_bytes,$slice_end);
|
||||
for(my $i=0;$i<=$#data;$i++){
|
||||
# Get Number of DataBytes
|
||||
$SType = $data[$i];
|
||||
if(defined($data{JEECONF}{$SType}{DataBytes})){
|
||||
$data_bytes = $data{JEECONF}{$SType}{DataBytes};
|
||||
###
|
||||
$SPre = $data{JEECONF}{$SType}{Prefix};
|
||||
$i++;
|
||||
$slice_end = $i + $data_bytes - 1;
|
||||
@SData = @data[$i..$slice_end];
|
||||
$DispData = $SPre . " " . $NodeID . " " . $SType . " " . join(" ",@SData);
|
||||
}
|
||||
else {
|
||||
Log $ll, "$name JEE-DISP: -ERROR- SensorType $SType not defined";
|
||||
return undef;
|
||||
}
|
||||
# Dispacth-Data to FHEM-Dispatcher -----------------------------------------
|
||||
#foreach my $m (sort keys %{$modules{JeeLink}{MatchList}}) {
|
||||
# my $match = $modules{JeeLink}{MatchList}{$m};
|
||||
$defs{$name}{"${name}_MSGCNT"}++;
|
||||
$defs{$name}{"${name}_TIME"} = TimeNow();
|
||||
$defs{$name}{RAWMSG} = $DispData;
|
||||
my %addvals = (RAWMSG => $DispData);
|
||||
my $hash = $defs{$name};
|
||||
Log $ll,"$name JEE-DISP: SType=$SType -> DispData=$DispData";
|
||||
my $ret_disp = &Dispatch($hash, $DispData, \%addvals);
|
||||
#}
|
||||
# Dispacth-Data to FHEM-Dispatcher -----------------------------------------
|
||||
# Minimum 2Bytes left
|
||||
# if((int(@data) - $i) < 2 ) {
|
||||
# Log $ll,"$name JEE-DISP: 2Byte $i -> " . int(@data);
|
||||
# $i = int(@data);
|
||||
# }
|
||||
#else {$i = $slice_end;}
|
||||
$i = $slice_end;
|
||||
}
|
||||
}
|
||||
################################################################################
|
||||
sub JEE_RF12MSG($$$){
|
||||
my ($rawdata,$name,$ll) = @_;
|
||||
# ^ i23* g212 @ 868 MHz
|
||||
# i -> NodeID
|
||||
# g -> NetGroup
|
||||
# @ -> 868MHz or 492MHz
|
||||
Log $ll,("$name/JeeLink RF12MSG: $rawdata");
|
||||
my($NodeID,$NetGroup,$Freq);
|
||||
if ( $rawdata =~ m/(^.*i)([0-9]{1,2})(\*.g)([0-9]{1,3})(.@.)([0-9]{1,3})(.MHz.*)/) {
|
||||
($NodeID,$NetGroup,$Freq) = ($2,$4,$6);
|
||||
Log $ll,("$name/JeeLink RF12MSG-CONFIG: NodeId:$NodeID NetGroup:$NetGroup Freq:$Freq");
|
||||
$defs{$name}{RF12_NodeID} = $NodeID;
|
||||
$defs{$name}{RF12_NetGroup} = $NetGroup;
|
||||
$defs{$name}{RF12_Frequenz} = $Freq;
|
||||
|
||||
}
|
||||
if($rawdata =~ m/\s+DF/){
|
||||
Log $ll,("$name/JeeLink RF12MSG-FLASH: $rawdata");
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
################################################################################
|
||||
sub JEE_IOWrite() {
|
||||
my ($hash, $msg,) = @_;
|
||||
return if(!$hash);
|
||||
# LogLevel
|
||||
my $name = $hash->{NAME};
|
||||
my $ll = 4;
|
||||
if(defined($attr{$name}{loglevel})) {
|
||||
$ll = $attr{$name}{loglevel};
|
||||
}
|
||||
if(defined($attr{$name}{dummy})){
|
||||
Log $ll ,"JEE-IOWRITE[DUMMY-MODE]: " . $hash->{NAME} . " $msg";
|
||||
}
|
||||
else {
|
||||
Log $ll ,"JEE-IOWRITE: " . $name . " $msg";
|
||||
$hash->{USBDev}->write($msg . "\n");
|
||||
select(undef, undef, undef, 0.001);
|
||||
}
|
||||
}
|
||||
################################################################################
|
||||
sub JEE_Write() {
|
||||
my ($hash, $msg1, $msg2) = @_;
|
||||
# $hash -> Received form Device
|
||||
# $msg1 -> Message Type ???
|
||||
# $msg2 -> Data
|
||||
return if(!$hash);
|
||||
# LogLevel
|
||||
my $name = $hash->{NAME};
|
||||
my $ll = 4;
|
||||
if(defined($attr{$name}{loglevel})) {
|
||||
$ll = $attr{$name}{loglevel};
|
||||
}
|
||||
Log $ll ,"JEE-WRITE: " . $hash->{NAME} . " MSG-1-: $msg1 MSG-2-: $msg2";
|
||||
# Default --------------------------------------------------------------------
|
||||
my $msg = $msg2;
|
||||
# FS20 -----------------------------------------------------------------------
|
||||
# JEE-WRITE: JL01 MSG: 04 BTN: 010101 1234 33 00
|
||||
# FS20.pm
|
||||
# IOWrite($hash, "04", "010101" . $hash->{XMIT} . $hash->{BTN} . $c);
|
||||
# MSG-1-: 04 MSG-2-: 01010177770311
|
||||
# <hchi>,<hclo>,<addr>,<cmd> f - FS20 command (868 MHz)
|
||||
# substr($jeedata, 0, 2);
|
||||
my ($hchi,$hclo,$addr,$cmd);
|
||||
if($msg2 =~ m/^010101/) {
|
||||
$msg2 =~s/010101//;
|
||||
Log 0, "JEE-IOWRITE-FS20: $msg2";
|
||||
|
||||
$hchi = hex(substr($msg2,0,2));
|
||||
$hclo = substr($msg2,2,2);
|
||||
$addr = hex(substr($msg2,4,2));
|
||||
$cmd = hex(substr($msg2,6,2));
|
||||
|
||||
$msg = "$hchi,$hclo,$addr,$cmd f";
|
||||
Log $ll, "JEE-IOWRITE-FS20: hchi:$hchi hclo:$hclo addr:$addr cmd:$cmd";
|
||||
|
||||
$hash->{FS20_LastSend} = TimeNow() . ":" . $msg ;
|
||||
}
|
||||
# FS20 -----------------------------------------------------------------------
|
||||
|
||||
if(defined($attr{$name}{dummy})){
|
||||
Log $ll, "JEE_Write[DUMMY-MODE]: >$msg<";
|
||||
}
|
||||
else {
|
||||
# Send Message >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
$hash->{USBDev}->write($msg . "\n");
|
||||
Log $ll, "JEE_Write >$msg<";
|
||||
select(undef, undef, undef, 0.001);
|
||||
# Send Message >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
}
|
||||
}
|
||||
################################################################################
|
||||
1;
|
261
fhem/contrib/JeeStuff/18_JME.pm
Normal file
261
fhem/contrib/JeeStuff/18_JME.pm
Normal file
@ -0,0 +1,261 @@
|
||||
################################################################################
|
||||
# FHEM-Modul see www.fhem.de
|
||||
# 18_JME.pm
|
||||
# JeeMeterNode
|
||||
#
|
||||
# Usage: define <Name> JME <Node-Nr>
|
||||
################################################################################
|
||||
# This program 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
################################################################################
|
||||
# Autor: Axel Rieger
|
||||
# Version: 1.0
|
||||
# Datum: 07.2011
|
||||
# Kontakt: fhem [bei] anax [punkt] info
|
||||
################################################################################
|
||||
# READINGs
|
||||
# MeterBase = MeterBase abgelesener Zaehlerstand...default 0
|
||||
# MeterNow = aktueller Zaehlerstand...wird hochgezŠhlt
|
||||
# Wenn MeterBase gesetzt ist, wird von dan an hochgezaehlt
|
||||
# Wenn MeterBase gesetzt wird, werden
|
||||
# AVG_Hour, AVG_Day, AVG_Month
|
||||
################################################################################
|
||||
package main;
|
||||
use strict;
|
||||
use warnings;
|
||||
use POSIX;
|
||||
use Data::Dumper;
|
||||
use vars qw(%defs);
|
||||
use vars qw(%attr);
|
||||
use vars qw(%data);
|
||||
use vars qw(%modules);
|
||||
################################################################################
|
||||
sub JME_Initialize($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
# Match/Prefix
|
||||
my $match = "JME";
|
||||
$hash->{Match} = "^JME";
|
||||
$hash->{DefFn} = "JME_Define";
|
||||
$hash->{UndefFn} = "JME_Undef";
|
||||
$hash->{SetFn} = "JME_Set";
|
||||
$hash->{ParseFn} = "JME_Parse";
|
||||
$hash->{AttrList} = "do_not_notify:0,1 loglevel:0,5 disable:0,1 TicksPerUnit avg_data_day avg_data_month";
|
||||
#-----------------------------------------------------------------------------
|
||||
# Arduino/JeeNodes-Variables:
|
||||
# http://arduino.cc/en/Reference/HomePage
|
||||
# Integer = 2 Bytes -> form -32,768 to 32,767
|
||||
# Long (unsigned) = 4 Bytes -> from 0 to 4,294,967,295
|
||||
# Long (signed) = 4 Bytes -> from -2,147,483,648 to 2,147,483,647
|
||||
#
|
||||
|
||||
# JeeConf
|
||||
# $data{JEECONF}{<SensorType>}{ReadingName}
|
||||
# $data{JEECONF}{<SensorType>}{DataBytes}
|
||||
# $data{JEECONF}{<SensorType>}{Prefix}
|
||||
# $data{JEECONF}{<SensorType>}{CorrFactor}
|
||||
# $data{JEECONF}{<SensorType>}{Function}
|
||||
# <SensorType>: 0-9 -> Reserved/not Used
|
||||
# <SensorType>: 10-99 -> Default
|
||||
# <SensorType>: 100-199 -> Userdifined
|
||||
# <SensorType>: 200-255 -> Internal/Test
|
||||
# Counter --------------------------------------------------------------------
|
||||
$data{JEECONF}{14}{ReadingName} = "counter";
|
||||
$data{JEECONF}{14}{DataBytes} = 2;
|
||||
$data{JEECONF}{14}{Prefix} = $match;
|
||||
}
|
||||
################################################################################
|
||||
sub JME_Define($){
|
||||
# define J001 JME <Node-Nr>
|
||||
# hash = New Device
|
||||
# defs = $a[0] <DEVICE-NAME> $a[1] DEVICE-TYPE $a[2]<Parameter-1-> $a[3]<Parameter-2->
|
||||
my ($hash, $def) = @_;
|
||||
my @a = split(/\s+/, $def);
|
||||
return "JME: Unknown argument count " . int(@a) . " , usage define <NAME>
|
||||
NodeID [<Path_to_User_Conf_File>]" if(int(@a) != 3);
|
||||
my $NodeID = $a[2];
|
||||
if(defined($modules{JME}{defptr}{$NodeID})) {
|
||||
return "Node $NodeID allready define";
|
||||
}
|
||||
$hash->{CODE} = $NodeID;
|
||||
$hash->{STATE} = "NEW: " . TimeNow();
|
||||
$hash->{OrderID} = ord($NodeID);
|
||||
$modules{JME}{defptr}{ord($NodeID)} = $hash;
|
||||
|
||||
# Init
|
||||
#$hash->{READINGS}{MeterBase}{TIME} = TimeNow();
|
||||
#$hash->{READINGS}{MeterBase}{VAL} = 0;
|
||||
#$hash->{READINGS}{MeterNow}{TIME} = TimeNow();
|
||||
#$hash->{READINGS}{MeterNow}{VAL} = 0;
|
||||
#$hash->{READINGS}{consumption}{TIME} = TimeNow();
|
||||
#$hash->{READINGS}{consumption}{VAL} = 0;
|
||||
#$hash->{READINGS}{current}{TIME} = TimeNow();
|
||||
#$hash->{READINGS}{current}{VAL} = 0;
|
||||
#$hash->{cnt_old} = 0;
|
||||
return undef;
|
||||
}
|
||||
################################################################################
|
||||
sub JME_Undef($$){
|
||||
my ($hash, $name) = @_;
|
||||
Log 4, "JME Undef: " . Dumper(@_);
|
||||
my $NodeID = $hash->{NodeID};
|
||||
if(defined($modules{JME}{defptr}{$NodeID})) {
|
||||
delete $modules{JME}{defptr}{$NodeID}
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
################################################################################
|
||||
sub JME_Set($)
|
||||
{
|
||||
my ($hash, @a) = @_;
|
||||
my $fields = "MeterBase MeterNow counter avg_day avg_month";
|
||||
return "Unknown argument $a[1], choose one of $fields" if($a[1] eq "?");
|
||||
|
||||
if($fields =~ m/$a[1]/){
|
||||
$hash->{READINGS}{$a[1]}{VAL} = sprintf("%0.3f",$a[2]);
|
||||
$hash->{READINGS}{$a[1]}{TIME} = TimeNow();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
################################################################################
|
||||
sub JME_Parse($$) {
|
||||
my ($iodev, $rawmsg) = @_;
|
||||
# $rawmsg = JeeNodeID + SensorType + SensorData
|
||||
# rawmsg = JME 03 252 03 65
|
||||
Log 4, "JME PARSE RAW-MSG: " . $rawmsg . " IODEV:" . $iodev->{NAME};
|
||||
#
|
||||
my @data = split(/\s+/,$rawmsg);
|
||||
my $NodeID = $data[1];
|
||||
# my $NodeID = sprintf("%02x" ,($data[1]));
|
||||
# $NodeID = hex($NodeID);
|
||||
# my $NodeID = chr(ord($data[1]));
|
||||
my $SType = $data[2];
|
||||
my $data_bytes = $data{JEECONF}{$SType}{DataBytes};
|
||||
my $data_end = int(@data) - 1;
|
||||
# $array[$#array];
|
||||
Log 4, "JME PARSE N:$NodeID S:$SType B:$data_bytes CNT:" . @data . " END:" . $data_end;
|
||||
my @SData = @data[3..$data_end];
|
||||
|
||||
my ($hash,$name);
|
||||
if(defined($modules{JME}{defptr}{ord($NodeID)})) {
|
||||
$hash = $modules{JME}{defptr}{ord($NodeID)};
|
||||
$name = $hash->{NAME};
|
||||
}
|
||||
else {
|
||||
return "UNDEFINED JME_$NodeID JME $NodeID";};
|
||||
my %readings;
|
||||
|
||||
# LogLevel
|
||||
my $ll = 5;
|
||||
if(defined($attr{$name}{loglevel})) {
|
||||
$ll = $attr{$name}{loglevel};
|
||||
}
|
||||
# Sensor-Data Bytes to Values
|
||||
# lowBit HighBit reverse ....
|
||||
@SData = reverse(@SData);
|
||||
my $raw_value = join("",@SData);
|
||||
my $value = "";
|
||||
map {$value .= sprintf "%02x",$_} @SData;
|
||||
$value = hex($value);
|
||||
Log $ll, "$name/JME-PARSE: $NodeID - $SType - " . join(" " , @SData) . " -> " . $value;
|
||||
|
||||
|
||||
my $TicksPerUnit = 0.1;
|
||||
if(defined($attr{$name}{TicksPerUnit})){
|
||||
$TicksPerUnit = $attr{$name}{TicksPerUnit};
|
||||
}
|
||||
|
||||
my $counter = 0;
|
||||
if(defined($defs{$name}{READINGS}{counter})){
|
||||
$counter = $defs{$name}{READINGS}{counter}{VAL};
|
||||
}
|
||||
|
||||
# Counter Reset at 100 to 0
|
||||
if($counter > 100) {
|
||||
$readings{counter} = 0;
|
||||
}
|
||||
else {$readings{counter} = $value;}
|
||||
|
||||
my ($current,$cnt_delta);
|
||||
$cnt_delta = $value - $counter;
|
||||
|
||||
$current = sprintf("%0.3f", ($cnt_delta * $TicksPerUnit));
|
||||
$readings{current} = $current;
|
||||
|
||||
|
||||
# Update only on Changes
|
||||
my ($MeterNow,$consumption,$MeterBase);
|
||||
$MeterNow = $defs{$name}{READINGS}{MeterNow}{VAL};
|
||||
if($current > 0 ){
|
||||
$MeterBase = $defs{$name}{READINGS}{MeterBase}{VAL};
|
||||
$readings{MeterNow} = sprintf("%0.3f", ($MeterNow + $current));
|
||||
$consumption = ($MeterNow + $current) - $MeterBase;
|
||||
$readings{consumption} = sprintf("%0.3f", $consumption);
|
||||
}
|
||||
#-----------------------------------------------------------------------------
|
||||
# Caculate AVG Day and Month
|
||||
#-----------------------------------------------------------------------------
|
||||
my $tsecs= time();
|
||||
my $d_now = (localtime($tsecs))[3];
|
||||
my $m_now = (localtime($tsecs))[4] + 1;
|
||||
# avg_data_day = Day | Day_MeterNow
|
||||
# avg_data_month = Month | Month_MeterNow
|
||||
my ($d, $d_mn,$m,$m_mn);
|
||||
if(defined($attr{$name}{avg_data_day})){
|
||||
($d, $d_mn) = split(/\|/,$attr{$name}{avg_data_day});
|
||||
($m,$m_mn) = split(/\|/,$attr{$name}{avg_data_month});
|
||||
}
|
||||
else {
|
||||
# INIT
|
||||
$defs{$name}{READINGS}{avg_day}{VAL} = 0.000;
|
||||
$defs{$name}{READINGS}{avg_day}{TIME} = TimeNow();
|
||||
$defs{$name}{READINGS}{avg_month}{VAL} = 0.000;
|
||||
$defs{$name}{READINGS}{avg_month}{TIME} = TimeNow();
|
||||
$attr{$name}{avg_data_day} = "$d_now|$MeterNow";
|
||||
$attr{$name}{avg_data_month} = "$m_now|$MeterNow";
|
||||
($d, $d_mn) = split(/\|/,$attr{$name}{avg_data_day});
|
||||
($m,$m_mn) = split(/\|/,$attr{$name}{avg_data_month});
|
||||
}
|
||||
Log $ll, "$name/JME-PARSE: D:NOW:$d_now/OLD:$d M:NOW:$m_now/OLD:$m";
|
||||
# AVG DAY
|
||||
if($d_now ne $d) {
|
||||
$consumption = ($MeterNow - $d_mn) + $defs{$name}{READINGS}{avg_day}{VAL} ;
|
||||
$consumption = $consumption / 2;
|
||||
$readings{avg_day} = sprintf("%0.3f", $consumption);
|
||||
$attr{$name}{avg_data_day} = "$d_now|$MeterNow";
|
||||
}
|
||||
# AVG Month
|
||||
if($m_now ne $m) {
|
||||
$consumption = ($MeterNow - $d_mn) + $defs{$name}{READINGS}{avg_month}{VAL} ;
|
||||
$consumption = $consumption / 2;
|
||||
$readings{avg_month} = sprintf("%0.3f", $consumption);
|
||||
$attr{$name}{avg_data_month} = "$m_now|$MeterNow";
|
||||
}
|
||||
#-----------------------------------------------------------------------------
|
||||
# Readings
|
||||
my $i = 0;
|
||||
foreach my $r (sort keys %readings) {
|
||||
Log 4, "JME $name $r:" . $readings{$r};
|
||||
$defs{$name}{READINGS}{$r}{VAL} = $readings{$r};
|
||||
$defs{$name}{READINGS}{$r}{TIME} = TimeNow();
|
||||
# Changed for Notify and Logs
|
||||
$defs{$name}{CHANGED}[$i] = $r . ": " . $readings{$r};
|
||||
$i++;
|
||||
}
|
||||
$defs{$name}{STATE} = "M:" . $defs{$name}{READINGS}{MeterNow}{VAL} . " C:$value";
|
||||
|
||||
return $name;
|
||||
}
|
||||
################################################################################
|
||||
1;
|
238
fhem/contrib/JeeStuff/18_JSN.pm
Normal file
238
fhem/contrib/JeeStuff/18_JSN.pm
Normal file
@ -0,0 +1,238 @@
|
||||
################################################################################
|
||||
# FHEM-Modul see www.fhem.de
|
||||
# 18_JSN.pm
|
||||
# JeeSensorNode
|
||||
#
|
||||
# Usage: define <Name> JSN <Node-Nr>
|
||||
################################################################################
|
||||
# This program 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
################################################################################
|
||||
# Autor: Axel Rieger
|
||||
# Version: 1.0
|
||||
# Datum: 07.2011
|
||||
# Kontakt: fhem [bei] anax [punkt] info
|
||||
################################################################################
|
||||
package main;
|
||||
use strict;
|
||||
use warnings;
|
||||
use POSIX;
|
||||
use Data::Dumper;
|
||||
use vars qw(%defs);
|
||||
use vars qw(%attr);
|
||||
use vars qw(%data);
|
||||
use vars qw(%modules);
|
||||
################################################################################
|
||||
sub JSN_Initialize($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
# Match/Prefix
|
||||
my $match = "JSN";
|
||||
$hash->{Match} = "^JSN";
|
||||
$hash->{DefFn} = "JSN_Define";
|
||||
$hash->{UndefFn} = "JSN_Undef";
|
||||
$hash->{ParseFn} = "JSN_Parse";
|
||||
$hash->{AttrList} = "do_not_notify:0,1 loglevel:0,5 disable:0,1";
|
||||
#-----------------------------------------------------------------------------
|
||||
# Arduino/JeeNodes-Variables:
|
||||
# http://arduino.cc/en/Reference/HomePage
|
||||
# Integer = 2 Bytes -> form -32,768 to 32,767
|
||||
# Long (unsigned) = 4 Bytes -> from 0 to 4,294,967,295
|
||||
# Long (signed) = 4 Bytes -> from -2,147,483,648 to 2,147,483,647
|
||||
#
|
||||
|
||||
# JeeConf
|
||||
# $data{JEECONF}{<SensorType>}{ReadingName}
|
||||
# $data{JEECONF}{<SensorType>}{DataBytes}
|
||||
# $data{JEECONF}{<SensorType>}{Prefix}
|
||||
# $data{JEECONF}{<SensorType>}{CorrFactor}
|
||||
# $data{JEECONF}{<SensorType>}{Function}
|
||||
# <SensorType>: 0-9 -> Reserved/not Used
|
||||
# <SensorType>: 10-99 -> Default
|
||||
# <SensorType>: 100-199 -> Userdifined
|
||||
# <SensorType>: 200-255 -> Internal/Test
|
||||
# Default-2-Bytes-------------------------------------------------------------
|
||||
$data{JEECONF}{12}{ReadingName} = "SensorData";
|
||||
$data{JEECONF}{12}{DataBytes} = 2;
|
||||
$data{JEECONF}{12}{Prefix} = $match;
|
||||
# Temperature ----------------------------------------------------------------
|
||||
$data{JEECONF}{11}{ReadingName} = "temperature";
|
||||
$data{JEECONF}{11}{DataBytes} = 2;
|
||||
$data{JEECONF}{11}{Prefix} = $match;
|
||||
$data{JEECONF}{11}{CorrFactor} = 0.1;
|
||||
# Brightness- ----------------------------------------------------------------
|
||||
$data{JEECONF}{12}{ReadingName} = "brightness";
|
||||
$data{JEECONF}{12}{DataBytes} = 4;
|
||||
$data{JEECONF}{12}{Prefix} = $match;
|
||||
# Triple-Axis-X-Y-Z----------------------------------------------------------
|
||||
$data{JEECONF}{13}{ReadingName} = "rtiple_axis";
|
||||
$data{JEECONF}{13}{Function} = "JSN_parse_12";
|
||||
$data{JEECONF}{13}{DataBytes} = 12;
|
||||
$data{JEECONF}{13}{Prefix} = $match;
|
||||
#-----------------------------------------------------------------------------
|
||||
# 14 Used by 18_JME
|
||||
# Counter --------------------------------------------------------------------
|
||||
# $data{JEECONF}{14}{ReadingName} = "counter";
|
||||
# $data{JEECONF}{14}{DataBytes} = 4;
|
||||
# $data{JEECONF}{14}{Prefix} = $match;
|
||||
# Pressure -------------------------------------------------------------------
|
||||
$data{JEECONF}{15}{ReadingName} = "pressure";
|
||||
$data{JEECONF}{15}{DataBytes} = 4;
|
||||
$data{JEECONF}{15}{CorrFactor} = 0.01;
|
||||
$data{JEECONF}{15}{Prefix} = $match;
|
||||
# Humidity -------------------------------------------------------------------
|
||||
$data{JEECONF}{16}{ReadingName} = "humidity";
|
||||
$data{JEECONF}{16}{DataBytes} = 1;
|
||||
$data{JEECONF}{16}{Prefix} = $match;
|
||||
# Light LDR ------------------------------------------------------------------
|
||||
$data{JEECONF}{17}{ReadingName} = "light_ldr";
|
||||
$data{JEECONF}{17}{DataBytes} = 1;
|
||||
$data{JEECONF}{17}{Prefix} = $match;
|
||||
# Motion ---------------------------------------------------------------------
|
||||
$data{JEECONF}{18}{ReadingName} = "motion";
|
||||
$data{JEECONF}{18}{DataBytes} = 1;
|
||||
$data{JEECONF}{18}{Prefix} = $match;
|
||||
# JeeNode InternalTemperatur -------------------------------------------------
|
||||
$data{JEECONF}{251}{ReadingName} = "AtmelTemp";
|
||||
$data{JEECONF}{251}{DataBytes} = 2;
|
||||
$data{JEECONF}{251}{Prefix} = $match;
|
||||
# JeeNode InternalRefVolatge -------------------------------------------------
|
||||
$data{JEECONF}{252}{ReadingName} = "PowerSupply";
|
||||
$data{JEECONF}{252}{DataBytes} = 2;
|
||||
$data{JEECONF}{252}{CorrFactor} = 0.0001;
|
||||
$data{JEECONF}{252}{Prefix} = $match;
|
||||
# JeeNode RF12 LowBat --------------------------------------------------------
|
||||
$data{JEECONF}{253}{ReadingName} = "RF12LowBat";
|
||||
$data{JEECONF}{253}{DataBytes} = 1;
|
||||
$data{JEECONF}{253}{Prefix} = $match;
|
||||
# JeeNode Milliseconds -------------------------------------------------------
|
||||
$data{JEECONF}{254}{ReadingName} = "Millis";
|
||||
$data{JEECONF}{254}{DataBytes} = 4;
|
||||
$data{JEECONF}{254}{Prefix} = $match;
|
||||
|
||||
}
|
||||
################################################################################
|
||||
sub JSN_Define($){
|
||||
# define J001 JSN <Node-Nr> [<Path_to_User_Conf_File>]
|
||||
# hash = New Device
|
||||
# defs = $a[0] <DEVICE-NAME> $a[1] DEVICE-TYPE $a[2]<Parameter-1-> $a[3]<Parameter-2->
|
||||
my ($hash, $def) = @_;
|
||||
my @a = split(/\s+/, $def);
|
||||
return "JSN: Unknown argument count " . int(@a) . " , usage define <NAME>
|
||||
NodeID [<Path_to_User_Conf_File>]" if(int(@a) != 3);
|
||||
my $NodeID = $a[2];
|
||||
if(defined($modules{JSN}{defptr}{$NodeID})) {
|
||||
return "Node $NodeID allready define";
|
||||
}
|
||||
$hash->{CODE} = $NodeID;
|
||||
$hash->{STATE} = "NEW: " . TimeNow();
|
||||
$hash->{OrderID} = $NodeID;
|
||||
$modules{JSN}{defptr}{$NodeID} = $hash;
|
||||
return undef;
|
||||
}
|
||||
################################################################################
|
||||
sub JSN_Undef($$){
|
||||
my ($hash, $name) = @_;
|
||||
Log 4, "JeeNode Undef: " . Dumper(@_);
|
||||
my $NodeID = $hash->{NodeID};
|
||||
if(defined($modules{JSN}{defptr}{$NodeID})) {
|
||||
delete $modules{JSN}{defptr}{$NodeID}
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
################################################################################
|
||||
sub JSN_Parse($$) {
|
||||
my ($iodev, $rawmsg) = @_;
|
||||
# $rawmsg = JeeNodeID + SensorType + SensorData
|
||||
# rawmsg = JSN 03 252 03 65
|
||||
Log 5, "JSN PARSE RAW-MSG: " . $rawmsg . " IODEV:" . $iodev->{NAME};
|
||||
#
|
||||
my @data = split(/\s+/,$rawmsg);
|
||||
my $NodeID = $data[1];
|
||||
# my $NodeID = sprintf("%02x" ,($data[1]));
|
||||
# $NodeID = hex($NodeID);
|
||||
# my $NodeID = chr(ord($data[1]));
|
||||
my $SType = $data[2];
|
||||
my $data_bytes = $data{JEECONF}{$SType}{DataBytes};
|
||||
my $data_end = int(@data) - 1;
|
||||
# $array[$#array];
|
||||
Log 5, "JSN PARSE N:$NodeID S:$SType B:$data_bytes CNT:" . @data . " END:" . $data_end;
|
||||
my @SData = @data[3..$data_end];
|
||||
|
||||
my ($hash,$name);
|
||||
if(defined($modules{JSN}{defptr}{$NodeID})) {
|
||||
$hash = $modules{JSN}{defptr}{$NodeID};
|
||||
$name = $hash->{NAME};
|
||||
}
|
||||
else {
|
||||
return "UNDEFINED JSN_$NodeID JSN $NodeID";};
|
||||
my %readings;
|
||||
# Function-Data --------------------------------------------------------------
|
||||
# If defined $data{JEECONF}{<SensorType>}{Function} then the function handels
|
||||
# data parsing...return a hash key:reading_name Value:reading_value
|
||||
# Param to Function: $iodev,$name,$NodeID, $SType,@SData
|
||||
# Function-Data --------------------------------------------------------------
|
||||
if(defined($data{JEECONF}{$SType}{Function})) {
|
||||
my $func = $data{JEECONF}{$SType}{Function};
|
||||
if(!defined(&$func)) {
|
||||
Log 0, "JSN PARSE Function not defined: $SType -> $func";
|
||||
return undef;
|
||||
}
|
||||
no strict "refs";
|
||||
%readings = &$func($iodev,$name,$NodeID, $SType,@SData);
|
||||
use strict "refs";
|
||||
}
|
||||
else {
|
||||
# Sensor-Data Bytes to Values
|
||||
# lowBit HighBit reverse ....
|
||||
@SData = reverse(@SData);
|
||||
my $raw_value = join("",@SData);
|
||||
my $value = "";
|
||||
map {$value .= sprintf "%02x",$_} @SData;
|
||||
$value = hex($value);
|
||||
Log 5, "JSN PARSE DATA $NodeID - $SType - " . join(" " , @SData) . " -> " . $value;
|
||||
|
||||
my $reading_name = $data{JEECONF}{$SType}{ReadingName};
|
||||
$readings{$reading_name} = $value;
|
||||
if(defined($data{JEECONF}{$SType}{CorrFactor})) {
|
||||
my $corr = $data{JEECONF}{$SType}{CorrFactor};
|
||||
$readings{$reading_name} = $value * $corr;
|
||||
}
|
||||
}
|
||||
#Reading
|
||||
my $i = 0;
|
||||
foreach my $r (sort keys %readings) {
|
||||
Log 5, "JSN $name $r:" . $readings{$r};
|
||||
$defs{$name}{READINGS}{$r}{VAL} = $readings{$r};
|
||||
$defs{$name}{READINGS}{$r}{TIME} = TimeNow();
|
||||
$defs{$name}{STATE} = TimeNow() . " " . $r;
|
||||
# Changed for Notify and Logs
|
||||
$defs{$name}{CHANGED}[$i] = $r . ": " . $readings{$r};
|
||||
$i++;
|
||||
}
|
||||
return $name;
|
||||
}
|
||||
################################################################################
|
||||
sub JSN_parse_12() {
|
||||
my ($iodev,$name,$NodeID, $SType,@SData) = @_;
|
||||
Log 5, "JSN PARSE-12 DATA $NodeID - $SType - " . join(" " , @SData);
|
||||
my %reading;
|
||||
$reading{X} = "XXX";
|
||||
$reading{Y} = "YYY";
|
||||
$reading{Z} = "ZZZ";
|
||||
return \%reading;
|
||||
|
||||
}
|
||||
################################################################################
|
||||
1;
|
179
fhem/contrib/JeeStuff/FHEM_JSN_BMP85.pde
Normal file
179
fhem/contrib/JeeStuff/FHEM_JSN_BMP85.pde
Normal file
@ -0,0 +1,179 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// JeeNode for Use with BMP085 and LuxPlug
|
||||
// reads out a BMP085 sensor connected via I2C
|
||||
// see http://news.jeelabs.org/2010/06/20/battery-savings-for-the-pressure-plug/
|
||||
// see http://news.jeelabs.org/2010/06/30/going-for-gold-with-the-bmp085/
|
||||
//
|
||||
// Baesd on RoomNode form JeeLabs roomNode.pde
|
||||
//
|
||||
// 2010-10-19 <jcw@equi4.com> http://opensource.org/licenses/mit-license.php
|
||||
// $Id: FHEM_JSN_BMP85.pde,v 1.1 2011-07-19 09:31:20 rudolfkoenig Exp $
|
||||
//
|
||||
// see http://jeelabs.org/2010/10/20/new-roomnode-code/
|
||||
// and http://jeelabs.org/2010/10/21/reporting-motion/
|
||||
// -----------------------------------------------------------------------------
|
||||
// Includes
|
||||
#include <Ports.h>
|
||||
#include <PortsSHT11.h>
|
||||
#include <RF12.h>
|
||||
#include <avr/sleep.h>
|
||||
#include <util/atomic.h>
|
||||
#include "PortsBMP085.h"
|
||||
// -----------------------------------------------------------------------------
|
||||
// JeeNode RF12-Config
|
||||
static byte myNodeID = 5; // node ID used for this unit
|
||||
static byte myNetGroup = 212; // netGroup used for this unit
|
||||
|
||||
// Port BMP085
|
||||
#define BMP_PORT 1
|
||||
|
||||
|
||||
// Payload aka Data to Send
|
||||
struct {
|
||||
// RF12LowBat
|
||||
byte rf12lowbat_type;
|
||||
byte rf12lowbat_data;
|
||||
// Temperature
|
||||
byte temp_type;
|
||||
int16_t temp_data;
|
||||
// Pressure
|
||||
byte pres_type;
|
||||
int32_t pres_data;
|
||||
|
||||
} payload;
|
||||
// -----------------------------------------------------------------------------
|
||||
// BMP085
|
||||
PortI2C one (BMP_PORT);
|
||||
BMP085 psensor (one, 3); // ultra high resolution
|
||||
MilliTimer timer;
|
||||
// -----------------------------------------------------------------------------
|
||||
// Config & Vars
|
||||
#define SERIAL 1 // set to 1 to also report readings on the serial port
|
||||
#define DEBUG 0 // set to 1 to display each loop()
|
||||
#define MEASURE_PERIOD 3000 // how often to measure, in tenths of seconds
|
||||
#define RETRY_PERIOD 10 // how soon to retry if ACK didn't come in
|
||||
#define RETRY_LIMIT 5 // maximum number of times to retry
|
||||
#define ACK_TIME 10 // number of milliseconds to wait for an ack
|
||||
#define REPORT_EVERY 1 // report every N measurement cycles
|
||||
#define SMOOTH 3 // smoothing factor used for running averages
|
||||
|
||||
// set the sync mode to 2 if the fuses are still the Arduino default
|
||||
// mode 3 (full powerdown) can only be used with 258 CK startup fuses
|
||||
#define RADIO_SYNC_MODE 2
|
||||
// -----------------------------------------------------------------------------
|
||||
// The scheduler makes it easy to perform various tasks at various times:
|
||||
enum { MEASURE, REPORT, TASK_END };
|
||||
|
||||
static word schedbuf[TASK_END];
|
||||
Scheduler scheduler (schedbuf, TASK_END);
|
||||
|
||||
static byte reportCount; // count up until next report, i.e. packet send
|
||||
|
||||
// has to be defined because we're using the watchdog for low-power waiting
|
||||
ISR(WDT_vect) { Sleepy::watchdogEvent(); }
|
||||
|
||||
// utility code to perform simple smoothing as a running average
|
||||
static int smoothedAverage(int prev, int next, byte firstTime =0) {
|
||||
if (firstTime)
|
||||
return next;
|
||||
return ((SMOOTH - 1) * prev + next + SMOOTH / 2) / SMOOTH;
|
||||
}
|
||||
// wait a few milliseconds for proper ACK to me, return true if indeed received
|
||||
static byte waitForAck() {
|
||||
MilliTimer ackTimer;
|
||||
while (!ackTimer.poll(ACK_TIME)) {
|
||||
if (rf12_recvDone() && rf12_crc == 0 &&
|
||||
rf12_hdr == (RF12_HDR_DST | RF12_HDR_ACK | myNodeID))
|
||||
return 1;
|
||||
set_sleep_mode(SLEEP_MODE_IDLE);
|
||||
sleep_mode();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// readout all the sensors and other values
|
||||
static void doMeasure() {
|
||||
// RF12lowBat
|
||||
payload.rf12lowbat_type = 253;
|
||||
payload.rf12lowbat_data = rf12_lowbat();
|
||||
|
||||
// sensor readout takes some time, so go into power down while waiting
|
||||
// payload.temp_data = psensor.measure(BMP085::TEMP);
|
||||
// payload.pres_data = psensor.measure(BMP085::PRES);
|
||||
|
||||
psensor.startMeas(BMP085::TEMP);
|
||||
Sleepy::loseSomeTime(16); // must wait at least 16 ms
|
||||
int32_t traw = psensor.getResult(BMP085::TEMP);
|
||||
|
||||
psensor.startMeas(BMP085::PRES);
|
||||
Sleepy::loseSomeTime(32);
|
||||
int32_t praw = psensor.getResult(BMP085::PRES);
|
||||
|
||||
payload.temp_type = 11;
|
||||
payload.pres_type = 15;
|
||||
psensor.calculate(payload.temp_data, payload.pres_data);
|
||||
}
|
||||
// periodic report, i.e. send out a packet and optionally report on serial port
|
||||
static void doReport() {
|
||||
rf12_sleep(-1);
|
||||
while (!rf12_canSend())
|
||||
rf12_recvDone();
|
||||
rf12_sendStart(0, &payload, sizeof payload, RADIO_SYNC_MODE);
|
||||
rf12_sleep(0);
|
||||
|
||||
#if SERIAL
|
||||
Serial.print("ROOM PAYLOAD: ");
|
||||
Serial.print("RF12LowBat: ");
|
||||
Serial.print((int) payload.rf12lowbat_data);
|
||||
Serial.print(" T: ");
|
||||
Serial.print(payload.temp_data);
|
||||
Serial.print(" P: ");
|
||||
Serial.print(payload.pres_data);
|
||||
Serial.println();
|
||||
delay(2); // make sure tx buf is empty before going back to sleep
|
||||
#endif
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
void setup () {
|
||||
rf12_initialize(myNodeID, RF12_868MHZ, myNetGroup);
|
||||
#if SERIAL || DEBUG
|
||||
Serial.begin(57600);
|
||||
Serial.print("\n[FHEM-JeeNode.3]");
|
||||
// myNodeID = rf12_config();
|
||||
#else
|
||||
|
||||
#endif
|
||||
|
||||
rf12_sleep(0); // power down
|
||||
// Start BMP085
|
||||
psensor.getCalibData();
|
||||
reportCount = REPORT_EVERY; // report right away for easy debugging
|
||||
scheduler.timer(MEASURE, 0); // start the measurement loop going
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
void loop () {
|
||||
#if DEBUG
|
||||
Serial.print('.');
|
||||
delay(2);
|
||||
#endif
|
||||
|
||||
switch (scheduler.pollWaiting()) {
|
||||
|
||||
case MEASURE:
|
||||
// reschedule these measurements periodically
|
||||
scheduler.timer(MEASURE, MEASURE_PERIOD);
|
||||
|
||||
doMeasure();
|
||||
|
||||
// every so often, a report needs to be sent out
|
||||
if (++reportCount >= REPORT_EVERY) {
|
||||
reportCount = 0;
|
||||
scheduler.timer(REPORT, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case REPORT:
|
||||
doReport();
|
||||
break;
|
||||
}
|
||||
}
|
167
fhem/contrib/JeeStuff/FHEM_JSN_LUX.pde
Normal file
167
fhem/contrib/JeeStuff/FHEM_JSN_LUX.pde
Normal file
@ -0,0 +1,167 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// JeeNode for Use with BMP085 and LuxPlug
|
||||
// reads out a BMP085 sensor connected via I2C
|
||||
// see http://news.jeelabs.org/2010/06/20/battery-savings-for-the-pressure-plug/
|
||||
// see http://news.jeelabs.org/2010/06/30/going-for-gold-with-the-bmp085/
|
||||
//
|
||||
// Baesd on RoomNode form JeeLabs roomNode.pde
|
||||
//
|
||||
// 2010-10-19 <jcw@equi4.com> http://opensource.org/licenses/mit-license.php
|
||||
// $Id: FHEM_JSN_LUX.pde,v 1.1 2011-07-19 09:31:20 rudolfkoenig Exp $
|
||||
//
|
||||
// see http://jeelabs.org/2010/10/20/new-roomnode-code/
|
||||
// and http://jeelabs.org/2010/10/21/reporting-motion/
|
||||
// -----------------------------------------------------------------------------
|
||||
// Includes
|
||||
#include <Ports.h>
|
||||
#include <PortsSHT11.h>
|
||||
#include <RF12.h>
|
||||
#include <avr/sleep.h>
|
||||
#include <util/atomic.h>
|
||||
// -----------------------------------------------------------------------------
|
||||
// JeeNode RF12-Config
|
||||
static byte myNodeID = 6; // node ID used for this unit
|
||||
static byte myNetGroup = 212; // netGroup used for this unit
|
||||
unsigned long lux;
|
||||
// Port Lux-Plug
|
||||
#define LUX_PORT 4
|
||||
|
||||
// Payload aka Data to Send
|
||||
struct {
|
||||
// RF12LowBat
|
||||
byte rf12lowbat_type;
|
||||
byte rf12lowbat_data;
|
||||
// Lux
|
||||
byte lux_type;
|
||||
unsigned long lux_data;
|
||||
|
||||
} payload;
|
||||
// -----------------------------------------------------------------------------
|
||||
// Lux Plug
|
||||
PortI2C two (LUX_PORT);
|
||||
LuxPlug lsensor (two, 0x39);
|
||||
byte highGain;
|
||||
MilliTimer timer;
|
||||
// -----------------------------------------------------------------------------
|
||||
// Config & Vars
|
||||
#define SERIAL 1 // set to 1 to also report readings on the serial port
|
||||
#define DEBUG 0 // set to 1 to display each loop()
|
||||
#define MEASURE_PERIOD 3000 // how often to measure, in tenths of seconds
|
||||
#define RETRY_PERIOD 10 // how soon to retry if ACK didn't come in
|
||||
#define RETRY_LIMIT 5 // maximum number of times to retry
|
||||
#define ACK_TIME 10 // number of milliseconds to wait for an ack
|
||||
#define REPORT_EVERY 1 // report every N measurement cycles
|
||||
#define SMOOTH 3 // smoothing factor used for running averages
|
||||
|
||||
// set the sync mode to 2 if the fuses are still the Arduino default
|
||||
// mode 3 (full powerdown) can only be used with 258 CK startup fuses
|
||||
#define RADIO_SYNC_MODE 2
|
||||
// -----------------------------------------------------------------------------
|
||||
// The scheduler makes it easy to perform various tasks at various times:
|
||||
enum { MEASURE, REPORT, TASK_END };
|
||||
|
||||
static word schedbuf[TASK_END];
|
||||
Scheduler scheduler (schedbuf, TASK_END);
|
||||
|
||||
static byte reportCount; // count up until next report, i.e. packet send
|
||||
|
||||
// has to be defined because we're using the watchdog for low-power waiting
|
||||
ISR(WDT_vect) { Sleepy::watchdogEvent(); }
|
||||
|
||||
// wait a few milliseconds for proper ACK to me, return true if indeed received
|
||||
static byte waitForAck() {
|
||||
MilliTimer ackTimer;
|
||||
while (!ackTimer.poll(ACK_TIME)) {
|
||||
if (rf12_recvDone() && rf12_crc == 0 &&
|
||||
rf12_hdr == (RF12_HDR_DST | RF12_HDR_ACK | myNodeID))
|
||||
return 1;
|
||||
set_sleep_mode(SLEEP_MODE_IDLE);
|
||||
sleep_mode();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// readout all the sensors and other values
|
||||
static void doMeasure() {
|
||||
// RF12lowBat
|
||||
payload.rf12lowbat_type = 253;
|
||||
payload.rf12lowbat_data = rf12_lowbat();
|
||||
// lux_demo.pde
|
||||
// need to wait after changing the gain
|
||||
// see http://talk.jeelabs.net/topic/608
|
||||
// highGain = ! highGain;
|
||||
// lsensor.setGain(highGain);
|
||||
// Sleepy::loseSomeTime(1000);
|
||||
// Lux Plug
|
||||
const word* p = lsensor.getData();
|
||||
lux = lsensor.calcLux();
|
||||
payload.lux_type = 12;
|
||||
payload.lux_data = lux;
|
||||
// payload.lux_data = lsensor.calcLux();
|
||||
|
||||
}
|
||||
// periodic report, i.e. send out a packet and optionally report on serial port
|
||||
static void doReport() {
|
||||
rf12_sleep(-1);
|
||||
while (!rf12_canSend())
|
||||
rf12_recvDone();
|
||||
rf12_sendStart(0, &payload, sizeof payload, RADIO_SYNC_MODE);
|
||||
rf12_sleep(0);
|
||||
|
||||
#if SERIAL
|
||||
Serial.print("ROOM PAYLOAD: ");
|
||||
Serial.print("RF12LowBat: ");
|
||||
Serial.print((int) payload.rf12lowbat_data);
|
||||
Serial.print(" L: ");
|
||||
Serial.print(payload.lux_data);
|
||||
Serial.println();
|
||||
delay(2); // make sure tx buf is empty before going back to sleep
|
||||
#endif
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
void setup () {
|
||||
rf12_initialize(myNodeID, RF12_868MHZ, myNetGroup);
|
||||
#if SERIAL
|
||||
Serial.begin(57600);
|
||||
Serial.print("\n[FHEM-JeeNode.3]");
|
||||
// myNodeID = rf12_config();
|
||||
#endif
|
||||
|
||||
rf12_sleep(0); // power down
|
||||
// Start Lux-Plug
|
||||
lsensor.begin();
|
||||
Sleepy::loseSomeTime(1000);
|
||||
highGain = 1;
|
||||
// highGain = ! highGain;
|
||||
lsensor.setGain(highGain);
|
||||
Sleepy::loseSomeTime(1000);
|
||||
reportCount = REPORT_EVERY; // report right away for easy debugging
|
||||
scheduler.timer(MEASURE, 0); // start the measurement loop going
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
void loop () {
|
||||
#if DEBUG
|
||||
Serial.print('.');
|
||||
delay(2);
|
||||
#endif
|
||||
|
||||
switch (scheduler.pollWaiting()) {
|
||||
|
||||
case MEASURE:
|
||||
// reschedule these measurements periodically
|
||||
scheduler.timer(MEASURE, MEASURE_PERIOD);
|
||||
|
||||
doMeasure();
|
||||
|
||||
// every so often, a report needs to be sent out
|
||||
if (++reportCount >= REPORT_EVERY) {
|
||||
reportCount = 0;
|
||||
scheduler.timer(REPORT, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case REPORT:
|
||||
doReport();
|
||||
break;
|
||||
}
|
||||
}
|
334
fhem/contrib/JeeStuff/FHEM_JSN_RoomNode.pde
Normal file
334
fhem/contrib/JeeStuff/FHEM_JSN_RoomNode.pde
Normal file
@ -0,0 +1,334 @@
|
||||
// New version of the Room Node, derived from rooms.pde
|
||||
// 2010-10-19 <jcw@equi4.com> http://opensource.org/licenses/mit-license.php
|
||||
// $Id: FHEM_JSN_RoomNode.pde,v 1.1 2011-07-19 09:31:20 rudolfkoenig Exp $
|
||||
|
||||
// see http://jeelabs.org/2010/10/20/new-roomnode-code/
|
||||
// and http://jeelabs.org/2010/10/21/reporting-motion/
|
||||
|
||||
// The complexity in the code below comes from the fact that newly detected PIR
|
||||
// motion needs to be reported as soon as possible, but only once, while all the
|
||||
// other sensor values are being collected and averaged in a more regular cycle.
|
||||
|
||||
#include <Ports.h>
|
||||
#include <PortsSHT11.h>
|
||||
#include <RF12.h>
|
||||
#include <avr/sleep.h>
|
||||
#include <util/atomic.h>
|
||||
|
||||
#define SERIAL 0 // set to 1 to also report readings on the serial port
|
||||
#define DEBUG 0 // set to 1 to display each loop() run and PIR trigger
|
||||
|
||||
#define SHT11_PORT 4 // defined if SHT11 is connected to a port
|
||||
#define LDR_PORT 1 // defined if LDR is connected to a port's AIO pin
|
||||
#define PIR_PORT 1 // defined if PIR is connected to a port's DIO pin
|
||||
|
||||
#define MEASURE_PERIOD 600 // how often to measure, in tenths of seconds
|
||||
#define RETRY_PERIOD 1 // how soon to retry if ACK didn't come in
|
||||
#define RETRY_LIMIT 1 // maximum number of times to retry
|
||||
#define ACK_TIME 5 // number of milliseconds to wait for an ack
|
||||
#define REPORT_EVERY 5 // report every N measurement cycles
|
||||
#define SMOOTH 3 // smoothing factor used for running averages
|
||||
|
||||
// set the sync mode to 2 if the fuses are still the Arduino default
|
||||
// mode 3 (full powerdown) can only be used with 258 CK startup fuses
|
||||
#define RADIO_SYNC_MODE 2
|
||||
|
||||
// The scheduler makes it easy to perform various tasks at various times:
|
||||
|
||||
enum { MEASURE, REPORT, TASK_END };
|
||||
|
||||
static word schedbuf[TASK_END];
|
||||
Scheduler scheduler (schedbuf, TASK_END);
|
||||
|
||||
// Other variables used in various places in the code:
|
||||
|
||||
static byte reportCount; // count up until next report, i.e. packet send
|
||||
static byte myNodeID = 8; // node ID used for this unit
|
||||
static byte myNetGroup = 212;
|
||||
|
||||
// This defines the structure of the packets which get sent out by wireless:
|
||||
/*
|
||||
struct {
|
||||
byte light; // light sensor: 0..255
|
||||
byte moved :1; // motion detector: 0..1
|
||||
byte humi :7; // humidity: 0..100
|
||||
int temp :10; // temperature: -500..+500 (tenths)
|
||||
byte lobat :1; // supply voltage dropped under 3.1V: 0..1
|
||||
} payload;
|
||||
*/
|
||||
struct {
|
||||
byte light_type;
|
||||
byte light_data;
|
||||
byte moved_type;
|
||||
byte moved_data;
|
||||
byte humi_type;
|
||||
byte humi_data;
|
||||
byte temp_type;
|
||||
int temp_data;
|
||||
byte rf12lowbat_type;
|
||||
byte rf12lowbat_data;
|
||||
} payload;
|
||||
// Conditional code, depending on which sensors are connected and how:
|
||||
|
||||
#if SHT11_PORT
|
||||
SHT11 sht11 (SHT11_PORT);
|
||||
#endif
|
||||
|
||||
#if LDR_PORT
|
||||
Port ldr (LDR_PORT);
|
||||
#endif
|
||||
|
||||
#if PIR_PORT
|
||||
#define PIR_HOLD_TIME 30 // hold PIR value this many seconds after change
|
||||
#define PIR_PULLUP 1 // set to one to pull-up the PIR input pin
|
||||
|
||||
class PIR : public Port {
|
||||
volatile byte value, changed;
|
||||
volatile uint32_t lastOn;
|
||||
public:
|
||||
PIR (byte portnum)
|
||||
: Port (portnum), value (0), changed (0), lastOn (0) {}
|
||||
|
||||
// this code is called from the pin-change interrupt handler
|
||||
void poll() {
|
||||
byte pin = digiRead();
|
||||
#if SERIAL
|
||||
Serial.print("PIR.POLL: ");
|
||||
Serial.print(pin,DEC);
|
||||
Serial.print(" LastOn: ");
|
||||
Serial.println(lastOn);
|
||||
#endif
|
||||
// if the pin just went on, then set the changed flag to report it
|
||||
if (pin) {
|
||||
if (!state())
|
||||
changed = 1;
|
||||
lastOn = millis();
|
||||
}
|
||||
value = pin;
|
||||
}
|
||||
|
||||
// state is true if curr value is still on or if it was on recently
|
||||
byte state() const {
|
||||
#if SERIAL
|
||||
Serial.print("ATOMIC_RESTORESTATE");
|
||||
Serial.print(" LastOn: ");
|
||||
Serial.println(lastOn);
|
||||
#endif
|
||||
byte f = value;
|
||||
if (lastOn > 0)
|
||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
|
||||
if (millis() - lastOn < 1000 * PIR_HOLD_TIME)
|
||||
f = 1;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
// return true if there is new motion to report
|
||||
byte triggered() {
|
||||
#if SERIAL
|
||||
Serial.print("TRIGGERD");
|
||||
Serial.print(" LastOn: ");
|
||||
Serial.println(lastOn);
|
||||
#endif
|
||||
byte f = changed;
|
||||
changed = 0;
|
||||
return f;
|
||||
}
|
||||
};
|
||||
|
||||
PIR pir (PIR_PORT);
|
||||
|
||||
// the PIR signal comes in via a pin-change interrupt
|
||||
ISR(PCINT2_vect) { pir.poll(); }
|
||||
#endif
|
||||
|
||||
// has to be defined because we're using the watchdog for low-power waiting
|
||||
ISR(WDT_vect) { Sleepy::watchdogEvent(); }
|
||||
|
||||
// utility code to perform simple smoothing as a running average
|
||||
static int smoothedAverage(int prev, int next, byte firstTime =0) {
|
||||
if (firstTime)
|
||||
return next;
|
||||
return ((SMOOTH - 1) * prev + next + SMOOTH / 2) / SMOOTH;
|
||||
}
|
||||
|
||||
// spend a little time in power down mode while the SHT11 does a measurement
|
||||
static void shtDelay () {
|
||||
Sleepy::loseSomeTime(32); // must wait at least 20 ms
|
||||
}
|
||||
|
||||
// wait a few milliseconds for proper ACK to me, return true if indeed received
|
||||
static byte waitForAck() {
|
||||
MilliTimer ackTimer;
|
||||
while (!ackTimer.poll(ACK_TIME)) {
|
||||
if (rf12_recvDone() && rf12_crc == 0 &&
|
||||
rf12_hdr == (RF12_HDR_DST | RF12_HDR_ACK | myNodeID))
|
||||
return 1;
|
||||
set_sleep_mode(SLEEP_MODE_IDLE);
|
||||
sleep_mode();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// readout all the sensors and other values
|
||||
static void doMeasure() {
|
||||
#if SERIAL
|
||||
Serial.println("doMeasure");
|
||||
#endif
|
||||
byte firstTime = payload.humi_data == 0; // special case to init running avg
|
||||
|
||||
// RF12lowBat
|
||||
payload.rf12lowbat_type = 253;
|
||||
payload.rf12lowbat_data = rf12_lowbat();
|
||||
|
||||
#if SHT11_PORT
|
||||
#ifndef __AVR_ATtiny84__
|
||||
sht11.measure(SHT11::HUMI, shtDelay);
|
||||
sht11.measure(SHT11::TEMP, shtDelay);
|
||||
float h, t;
|
||||
sht11.calculate(h, t);
|
||||
int humi = h + 0.5, temp = 10 * t + 0.5;
|
||||
#else
|
||||
//XXX TINY!
|
||||
int humi = 50, temp = 25;
|
||||
#endif
|
||||
|
||||
payload.humi_type = 16;
|
||||
payload.humi_data = smoothedAverage(payload.humi_data, humi, firstTime);
|
||||
payload.temp_type = 11;
|
||||
payload.temp_data = smoothedAverage(payload.temp_data, temp, firstTime);
|
||||
#endif
|
||||
#if LDR_PORT
|
||||
ldr.digiWrite2(1); // enable AIO pull-up
|
||||
byte light = ~ ldr.anaRead() >> 2;
|
||||
ldr.digiWrite2(0); // disable pull-up to reduce current draw
|
||||
|
||||
payload.light_type = 17;
|
||||
payload.light_data = smoothedAverage(payload.light_data, light, firstTime);
|
||||
#endif
|
||||
#if PIR_PORT
|
||||
payload.moved_type = 18;
|
||||
payload.moved_data = pir.state();
|
||||
#endif
|
||||
}
|
||||
|
||||
// periodic report, i.e. send out a packet and optionally report on serial port
|
||||
static void doReport() {
|
||||
Serial.println("REPORT");
|
||||
rf12_sleep(-1);
|
||||
while (!rf12_canSend())
|
||||
rf12_recvDone();
|
||||
rf12_sendStart(0, &payload, sizeof payload, RADIO_SYNC_MODE);
|
||||
rf12_sleep(0);
|
||||
|
||||
#if SERIAL
|
||||
Serial.print("ROOM L:");
|
||||
Serial.print((int) payload.light_data);
|
||||
Serial.print(" M:");
|
||||
Serial.print((int) payload.moved_data);
|
||||
Serial.print(" H:");
|
||||
Serial.print((int) payload.humi_data);
|
||||
Serial.print(" T:");
|
||||
Serial.print((int) payload.temp_data);
|
||||
Serial.print(" LB:");
|
||||
Serial.print((int) payload.rf12lowbat_data);
|
||||
Serial.println();
|
||||
delay(2); // make sure tx buf is empty before going back to sleep
|
||||
#endif
|
||||
}
|
||||
|
||||
// send packet and wait for ack when there is a motion trigger
|
||||
static void doTrigger() {
|
||||
#if DEBUG
|
||||
Serial.print("doTrigger PIR ");
|
||||
Serial.print((int) payload.moved_data);
|
||||
delay(2);
|
||||
#endif
|
||||
|
||||
for (byte i = 0; i < RETRY_LIMIT; ++i) {
|
||||
rf12_sleep(-1);
|
||||
while (!rf12_canSend())
|
||||
rf12_recvDone();
|
||||
rf12_sendStart(RF12_HDR_ACK, &payload, sizeof payload, RADIO_SYNC_MODE);
|
||||
byte acked = waitForAck();
|
||||
rf12_sleep(0);
|
||||
|
||||
if (acked) {
|
||||
#if DEBUG
|
||||
Serial.print(" ack ");
|
||||
Serial.println((int) i);
|
||||
delay(2);
|
||||
#endif
|
||||
// reset scheduling to start a fresh measurement cycle
|
||||
scheduler.timer(MEASURE, MEASURE_PERIOD);
|
||||
return;
|
||||
}
|
||||
|
||||
Sleepy::loseSomeTime(RETRY_PERIOD * 100);
|
||||
}
|
||||
scheduler.timer(MEASURE, MEASURE_PERIOD);
|
||||
#if DEBUG
|
||||
Serial.println(" no ack!");
|
||||
delay(2);
|
||||
#endif
|
||||
}
|
||||
|
||||
void setup () {
|
||||
#if SERIAL || DEBUG
|
||||
Serial.begin(57600);
|
||||
Serial.print("\n[roomNode.3]");
|
||||
// myNodeID = rf12_config();
|
||||
rf12_initialize(myNodeID, RF12_868MHZ, myNetGroup);
|
||||
#else
|
||||
rf12_initialize(myNodeID, RF12_868MHZ, myNetGroup);
|
||||
#endif
|
||||
|
||||
rf12_sleep(0); // power down
|
||||
|
||||
#if PIR_PORT
|
||||
pir.digiWrite(PIR_PULLUP);
|
||||
#ifdef PCMSK2
|
||||
bitSet(PCMSK2, PIR_PORT + 3);
|
||||
bitSet(PCICR, PCIE2);
|
||||
#else
|
||||
//XXX TINY!
|
||||
#endif
|
||||
#endif
|
||||
|
||||
reportCount = REPORT_EVERY; // report right away for easy debugging
|
||||
scheduler.timer(MEASURE, 0); // start the measurement loop going
|
||||
}
|
||||
|
||||
void loop () {
|
||||
#if DEBUG
|
||||
Serial.println('Loop..................................................');
|
||||
delay(2);
|
||||
#endif
|
||||
|
||||
#if PIR_PORT
|
||||
if (pir.triggered()) {
|
||||
payload.moved_data = pir.state();
|
||||
doTrigger();
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (scheduler.pollWaiting()) {
|
||||
|
||||
case MEASURE:
|
||||
// reschedule these measurements periodically
|
||||
scheduler.timer(MEASURE, MEASURE_PERIOD);
|
||||
|
||||
doMeasure();
|
||||
|
||||
// every so often, a report needs to be sent out
|
||||
if (++reportCount >= REPORT_EVERY) {
|
||||
reportCount = 0;
|
||||
scheduler.timer(REPORT, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case REPORT:
|
||||
doReport();
|
||||
break;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user