package main; use strict; use warnings; use IO::Socket; sub CommandUpdatefhem($$); sub CommandCULflash($$); my $server = "fhem.de:80"; my $sdir = "/fhemupdate"; my $ftime = "filetimes.txt"; my $dfu = "dfu-programmer"; ##################################### sub updatefhem_Initialize($$) { my %fhash = ( Fn=>"CommandUpdatefhem", Hlp=>",update fhem from the nightly CVS" ); $cmds{updatefhem} = \%fhash; my %chash = ( Fn=>"CommandCULflash", Hlp=>" ,flash the CUL from the nightly CVS" ); $cmds{CULflash} = \%chash; } ##################################### sub CommandUpdatefhem($$) { my ($cl, $param) = @_; my $lt = ""; my $ret = ""; my $moddir = "$attr{global}{modpath}/FHEM"; #my $moddir = "XXX"; # Read in the OLD filetimes.txt my %oldtime; if(open FH, "$moddir/$ftime") { while(my $l = ) { chomp($l); my ($ts, $fs, $file) = split(" ", $l, 3); $oldtime{$file} = $ts; } close(FH); } my $filetimes = GetHttpFile($server, "$sdir/$ftime"); return "Can't get $ftime from $server" if(!$filetimes); my (%filetime, %filesize); foreach my $l (split("[\r\n]", $filetimes)) { chomp($l); return "Corrupted filetimes.txt file" if($l !~ m/^20\d\d-\d\d-\d\d_\d\d:\d\d:\d\d /); my ($ts, $fs, $file) = split(" ", $l, 3); $filetime{$file} = $ts; $filesize{$file} = $fs; } my @reload; my $newfhem = 0; foreach my $f (sort keys %filetime) { if($param) { next if($f ne $param); } else { next if($oldtime{$f} && $filetime{$f} eq $oldtime{$f}); next if($f =~ m/.hex$/); # skip firmware files } my $localfile = "$moddir/$f"; my $remfile = $f; if($f eq "fhem.pl") { $ret .= "updated fhem.pl, restart of fhem is required\n"; $newfhem = 1; $localfile = $0; $remfile = "$f.txt"; } if($f =~ m/^(\d\d_)(.*).pm$/) { my $m = $2; push @reload, $f if($modules{$m} && $modules{$m}{LOADED}); } my $content = GetHttpFile($server, "$sdir/$remfile"); return "File size for $f does not correspond to filetimes.txt entry" if(length($content) ne $filesize{$f}); open(FH,">$localfile") || return "Can't write $localfile"; print FH $content; close(FH) } return "Can't write $moddir/$ftime" if(!open(FH, ">$moddir/$ftime")); print FH $filetimes; close(FH); if(!$newfhem) { foreach my $m (@reload) { $ret .= "reloading module $m\n"; my $cret = CommandReload($cl, $m); return "$ret$cret" if($cret); } } return $ret; } sub CommandCULflash($$) { my ($cl, $param) = @_; my $moddir = "$attr{global}{modpath}/FHEM"; #my $moddir = "XXX"; my %ctypes = ( CUL_V2 => "at90usb162", CUL_V2_HM => "at90usb162", CUL_V3 => "atmega32u4", CUL_V4 => "atmega32u2", ); my @a = split("[ \t]+", $param); return "Usage: CULflash , ". "where is one of ". join(" ", sort keys %ctypes) if(int(@a) != 2 || !$defs{$a[0]} || $defs{$a[0]}{TYPE} ne "CUL" || !$ctypes{$a[1]}); my $cul = $a[0]; my $target = $a[1]; ################################ # First get the index file to prove the file size my $filetimes = GetHttpFile($server, "$sdir/$ftime"); return "Can't get $ftime from $server" if(!$filetimes); my (%filetime, %filesize); foreach my $l (split("[\r\n]", $filetimes)) { chomp($l); return "Corrupted filetimes.txt file" if($l !~ m/^20\d\d-\d\d-\d\d_\d\d:\d\d:\d\d /); my ($ts, $fs, $file) = split(" ", $l, 3); $filetime{$file} = $ts; $filesize{$file} = $fs; } ################################ # Now get the firmware file: my $content = GetHttpFile($server, "$sdir/$target.hex"); return "File size for $target.hex does not correspond to filetimes.txt entry" if(length($content) ne $filesize{"$target.hex"}); my $localfile = "$moddir/$target.hex"; open(FH,">$localfile") || return "Can't write $localfile"; print FH $content; close(FH); my $cmd = "($dfu MCU erase && $dfu MCU flash TARGET && $dfu MCU start) 2>&1"; my $mcu = $ctypes{$target}; $cmd =~ s/MCU/$mcu/g; $cmd =~ s/TARGET/$localfile/g; CUL_SimpleWrite($defs{CUL}, "B01"); sleep(4); # B01 needs 2 seconds for the reset Log 1, $cmd; my $result = `$cmd`; Log 1, $result; return $result; } sub GetHttpFile($$) { my ($host, $filename) = @_; my $server = IO::Socket::INET->new(PeerAddr => $server); if(!$server) { Log 1, "Can't connect to $server\n"; return undef; } $host =~ s/:.*//; my $req = "GET $filename HTTP/1.0\r\nHost: $host\r\n\r\n\r\n"; syswrite $server, $req; my ($buf, $ret); while(sysread($server, $buf, 65536) > 0) { $ret .= $buf; } $ret=~ s/.*?\r\n\r\n//s; Log 1, "Got http://$host$filename, length: ".length($ret); return $ret; } 1;