#!/usr/bin/perl use warnings; use strict; use English; use POSIX; use Device::SerialPort; use Net::MQTT::Simple; # config my $delay = 1; my $verbose = 1; my @paths = ( "unused", "unused", "unused", "temperature/elv/1", "temperature/elv/2", "temperature/elv/3", "temperature/elv/4", "temperature/elv/5", "temperature/elv/6", "temperature/elv/7", "temperature/elv/8", "humidity/elv/1", "humidity/elv/2", "humidity/elv/3", "humidity/elv/4", "humidity/elv/5", "humidity/elv/6", "humidity/elv/7", "humidity/elv/8", "temperature/elv/0", "humidity/elv/0", "wind/elv/0", "rain/elv/0", "is-raining/elv/0", "unused" ); ###################################################################### # vars my $host = shift; my $base = shift; my $port = shift; my ($elv,$mqtt,$line,@data,@prev,$updates,$topic,$value); # handle args my @devs = glob("/dev/serial/by-id/usb-*ELV_USB-WDE1*"); $base = "sensors" unless defined($base); $port = shift @devs unless defined($port); if (!defined($host)) { print "usage: $0 [ [ ] ]\n"; print "default for topic-prefix: $base\n"; print "default for serial-port : $port\n"; exit 1; } # init serial port $elv = new Device::SerialPort($port, 1) or die "open serial port ($port): $!"; $elv->baudrate(9600); $elv->parity('none'); $elv->databits(8); $elv->stopbits(1); $elv->write_settings(); # init mqtt $mqtt = Net::MQTT::Simple->new($host) or die "mqtt init (server $host)"; # detect and init elv reader $elv->write("?"); sleep $delay; $line = $elv->input; die "ELV USB-WDE1 not detected on $port" unless $line =~ m/ELV USB-WDE1/; $elv->write("M2"); sleep $delay; $line = $elv->input; die "switch to logview mode failed" unless $line =~ m/LogView/; $elv->write("RESET"); sleep $delay; $line = $elv->input; die "reset failed (#1)" unless $line =~ m/OK/; $elv->write("?"); sleep $delay; $line = $elv->input; die "reset failed (#2)" unless $line =~ m/ELV USB-WDE1/; print "init ok, waiting for data ...\n" if $verbose; # polling loop $OUTPUT_AUTOFLUSH = 1; while (1) { # read data sleep $delay; if (!defined($elv->status)) { die "serial line dead"; } $line = $elv->input; next if $line eq ""; @data = split /;/, $line; if (scalar(@data) != scalar(@paths)) { sleep $delay; $line .= $elv->input; @data = split /;/, $line; } if (scalar(@data) != scalar(@paths)) { printf "data error (%d != %d), fixup failed\n", scalar(@data), scalar(@paths); next; } # ping mqtt $mqtt->tick( 1 ); $updates = 0; for my $i (0 .. (scalar(@paths) - 1)) { next if $paths[$i] eq "unused"; # update mqtt $topic = $base . "/" . $paths[$i]; $value = $data[$i]; $value =~ s/,/./; # de -> us float format $mqtt->retain( $topic => $value ); # log changes if ((!defined($prev[$i]) || $data[$i] ne $prev[$i]) && $verbose) { $updates++; if ($updates == 1) { print strftime("\n[%H:%M:%S]\n", localtime()); } printf " %-32s:%8s\n", $topic, $value; } } @prev = @data; }