2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-10 03:06:37 +00:00

HMCCU: Optimized week program display

git-svn-id: https://svn.fhem.de/fhem/trunk@28793 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
zap 2024-04-14 11:57:19 +00:00
parent ef2b5cac14
commit d0d5f3013d
4 changed files with 123 additions and 136 deletions

View File

@ -35,6 +35,7 @@ use warnings;
use Encode qw(decode encode);
use RPC::XML::Client;
use RPC::XML::Server;
use JSON;
use HttpUtils;
use SetExtensions;
use HMCCUConf;
@ -57,7 +58,7 @@ my %HMCCU_CUST_CHN_DEFAULTS;
my %HMCCU_CUST_DEV_DEFAULTS;
# HMCCU version
my $HMCCU_VERSION = '5.0 2024-03';
my $HMCCU_VERSION = '5.0 2024-04';
# Timeout for CCU requests (seconds)
my $HMCCU_TIMEOUT_REQUEST = 4;
@ -290,7 +291,6 @@ sub HMCCU_GetDeviceList ($);
sub HMCCU_GetDeviceModel ($$$;$);
sub HMCCU_GetDeviceName ($$;$);
sub HMCCU_GetDeviceType ($$$);
sub HMCCU_GetFirmwareVersions ($$);
sub HMCCU_GetParamDef ($$$;$);
sub HMCCU_GetReceivers ($$$);
sub HMCCU_IsValidChannel ($$$);
@ -484,8 +484,8 @@ sub HMCCU_Define ($$$)
# Check if authentication is active
my ($username, $password) = HMCCU_GetCredentials ($hash);
$hash->{authentication} = $username ne '' && $password ne '' ? 'on' : 'off';
($username, $password) = HMCCU_GetCredentials ($hash, '_json_');
$hash->{json} = $username ne '' && $password ne '' ? 'on' : 'off';
$hash->{json} = HMCCU_JSONLogin ($hash) ? 'on' : 'off';
HMCCU_Log ($hash, 1, "Initialized version $HMCCU_VERSION");
@ -1521,6 +1521,13 @@ sub HMCCU_Set ($@)
my $err = HMCCU_SetCredentials ($hash, $credKey, $username, $password);
return HMCCU_SetError ($hash, "Can't store credentials. $err") if (defined($err));
if ($credInt eq 'json') {
if (!HMCCU_JSONLogin ($hash)) {
$hash->{json} = 'off';
return HMCCU_SetError ($hash, "JSON API login failed");
}
}
$hash->{$credInt} = 'on';
return 'Credentials for CCU authentication stored';
}
@ -1761,7 +1768,7 @@ sub HMCCU_Get ($@)
$opt = lc($opt);
my $options = "create createDev detectDev defaults:noArg exportDefaults dutycycle:noArg vars update".
" paramsetDesc firmware rpcEvents:noArg rpcState:noArg deviceInfo".
" paramsetDesc rpcEvents:noArg rpcState:noArg deviceInfo".
" ccuMsg:alarm,service ccuConfig:noArg ccuDevices:noArg".
" internal:groups,interfaces,versions";
if (defined($hash->{hmccu}{ccuSuppDevList}) && $hash->{hmccu}{ccuSuppDevList} ne '') {
@ -1951,38 +1958,6 @@ sub HMCCU_Get ($@)
HMCCU_GetDutyCycle ($hash);
return HMCCU_SetState ($hash, 'OK');
}
elsif ($opt eq 'firmware') {
my $devtype = shift @$a // '.*';
my $dtexp = $devtype eq 'full' ? '.*' : $devtype;
my $dc = HMCCU_GetFirmwareVersions ($hash, $dtexp);
return 'Found no firmware downloads' if ($dc == 0);
$result = "Found $dc firmware downloads. Click on the new version number for download\n\n";
if ($devtype eq 'full') {
$result .= "Type Available Date\n".('-' x 41)."\n";
foreach my $ct (keys %{$hash->{hmccu}{type}}) {
$result .= sprintf "%-20s <a href=\"http://www.eq-3.de/%s\">%-9s</a> %-10s\n",
$ct, $hash->{hmccu}{type}{$ct}{download},
$hash->{hmccu}{type}{$ct}{firmware}, $hash->{hmccu}{type}{$ct}{date};
}
}
else {
my @devlist = HMCCU_FindClientDevices ($hash, "(HMCCUDEV|HMCCUCHN)");
return $result if (scalar (@devlist) == 0);
$result .=
"Device Type Current Available Date\n".('-' x 76)."\n";
foreach my $dev (@devlist) {
my $ch = $defs{$dev};
my $ct = uc($ch->{ccutype});
my $fw = $ch->{firmware} // 'N/A';
next if (!exists ($hash->{hmccu}{type}{$ct}) || $ct !~ /$dtexp/);
$result .= sprintf "%-25s %-20s %-7s <a href=\"http://www.eq-3.de/%s\">%-9s</a> %-10s\n",
$ch->{NAME}, $ct, $fw, $hash->{hmccu}{type}{$ct}{download},
$hash->{hmccu}{type}{$ct}{firmware}, $hash->{hmccu}{type}{$ct}{date};
}
}
return HMCCU_SetState ($hash, 'OK', $result);
}
elsif ($opt eq 'defaults') {
$result = HMCCU_GetDefaults ($hash, 1);
return HMCCU_SetState ($hash, 'OK', $result);
@ -5271,81 +5246,6 @@ sub HMCCU_FormatHashTable ($)
return $result;
}
######################################################################
# Get available firmware versions from EQ-3 server.
# Firmware version, date and download link are stored in hash
# {hmccu}{type}{$type} in elements {firmware}, {date} and {download}.
# Parameter type can be a regular expression matching valid Homematic
# device types in upper case letters. Default is '.*'.
# Return number of available firmware downloads.
######################################################################
sub HMCCU_GetFirmwareVersions ($$)
{
my ($hash, $type) = @_;
my $name = $hash->{NAME};
my $ccureqtimeout = AttrVal ($name, 'ccuReqTimeout', $HMCCU_TIMEOUT_REQUEST);
my $url = 'http://www.eq-3.de/service/downloads.html';
my $response = GetFileFromURL ($url, $ccureqtimeout, "suchtext=&suche_in=&downloadart=11");
my @download = $response =~ m/<a.href="(Downloads\/Software\/Firmware\/[^"]+)/g;
my $dc = 0;
my @ts = localtime (time);
$ts[4] += 1;
$ts[5] += 1900;
foreach my $dl (@download) {
my $dd = $ts[3];
my $mm = $ts[4];
my $yy = $ts[5];
my $fw;
my $date = "$dd.$mm.$yy";
my @path = split (/\//, $dl);
my $file = pop @path;
next if ($file !~ /(\.tgz|\.tar\.gz)/);
$file =~ s/_update_V?/\|/;
my ($dt, $rest) = split (/\|/, $file);
next if (!defined($rest));
$dt =~ s/_/-/g;
$dt = uc($dt);
next if ($dt !~ /$type/);
if ($rest =~ /^([\d_]+)([0-9]{2})([0-9]{2})([0-9]{2})\./) {
# Filename with version and date
($fw, $yy, $mm, $dd) = ($1, $2, $3, $4);
$yy += 2000 if ($yy < 100);
$date = "$dd.$mm.$yy";
$fw =~ s/_$//;
}
elsif ($rest =~ /^([\d_]+)\./) {
# Filename with version
$fw = $1;
}
else {
$fw = $rest;
}
$fw =~ s/_/\./g;
# Compare firmware dates
if (exists ($hash->{hmccu}{type}{$dt}{date})) {
my ($dd1, $mm1, $yy1) = split (/\./, $hash->{hmccu}{type}{$dt}{date});
my $v1 = $yy1*10000+$mm1*100+$dd1;
my $v2 = $yy*10000+$mm*100+$dd;
next if ($v1 > $v2);
}
$dc++;
$hash->{hmccu}{type}{$dt}{firmware} = $fw;
$hash->{hmccu}{type}{$dt}{date} = $date;
$hash->{hmccu}{type}{$dt}{download} = $dl;
}
return $dc;
}
######################################################################
# Read CCU device identified by device or channel name via Homematic
# Script.
@ -5402,9 +5302,6 @@ sub HMCCU_GetDevice ($$)
if (scalar(keys %objects) > 0) {
# Update HMCCU device tables
($devcount, $chncount) = HMCCU_UpdateDeviceTable ($hash, \%objects);
# Read available datapoints for device type
# HMCCU_GetDatapointList ($hash, $devname, $devtype) if (defined ($devname) && defined ($devtype));
}
return ($devcount, $chncount);
@ -5609,11 +5506,6 @@ sub HMCCU_GetDeviceList ($)
if (scalar (keys %objects) > 0) {
# Update HMCCU device tables
($devcount, $chncount) = HMCCU_UpdateDeviceTable ($hash, \%objects);
# Read available datapoints for each device type
# This will lead to problems if some devices have different firmware versions
# or links to system variables !
# HMCCU_GetDatapointList ($hash);
}
# Store group configurations
@ -5663,6 +5555,20 @@ sub HMCCU_GetDeviceList ($)
return ($devcount, $chncount, $ifcount, $prgcount, $gcount);
}
sub HMCCU_GetDeviceList2 ($)
{
my ($hash) = @_;
my $response = HMCCU_JSONRequest ($hash, qq(
{
"method": "Device.listAllDetail",
"params": {
"_session_id_": "$hash->{hmccu}{jsonAPI}{sessionId}"
}
}
));
}
######################################################################
# Check if device has an address, is not disabled and state is
# not inactive
@ -7073,6 +6979,7 @@ sub HMCCU_ExecuteRoleCommand ($@)
}
push @par, $value if (defined($value));
$cmdFnc{$cmdNo}{cmd} = $cmd;
$cmdFnc{$cmdNo}{fnc} = $cmd->{fnc};
$cmdFnc{$cmdNo}{par} = \@par;
}
@ -7129,7 +7036,7 @@ sub HMCCU_ExecuteRoleCommand ($@)
if ($cmdFnc{$cmdNo}{fnc} ne '') {
# :(
no strict "refs";
$disp .= &{$cmdFnc{$cmdNo}{fnc}}($ioHash, $clHash, $resp, @{$cmdFnc{$cmdNo}{par}});
$disp .= &{$cmdFnc{$cmdNo}{fnc}}($ioHash, $clHash, $resp, $cmdFnc{$cmdNo}{cmd}, @{$cmdFnc{$cmdNo}{par}});
use strict "refs";
}
}
@ -7626,28 +7533,36 @@ sub HMCCU_DisplayGetParameterResult ($$$)
sub HMCCU_DisplayWeekProgram ($$$;$$)
{
my ($ioHash, $clHash, $resp, $programName, $program) = @_;
my ($ioHash, $clHash, $resp, $cmd, $programName, $program) = @_;
$programName //= 'all';
$program //= 'all';
my @weekDay = ('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday');
my $convRes = HMCCU_UpdateParamsetReadings ($ioHash, $clHash, $resp);
return "No data available for week program(s) $program"
if (!exists($clHash->{hmccu}{tt}) || ($program ne 'all' && !exists($clHash->{hmccu}{tt}{$program})));
if (defined($cmd->{min}) && HMCCU_IsIntNum($cmd->{min}) && $cmd->{min} > 0) {
$program -= $cmd->{min};
HMCCU_Log ($clHash, 2, "program = $program, was ".$program+$cmd->{min});
}
my $s = '<html>';
foreach my $w (sort keys %{$clHash->{hmccu}{tt}}) {
next if ("$w" ne "$program" && "$program" ne 'all');
# $w-- if ("$program" eq "$programName" && HMCCU_IsIntNum($program) && $w > 0);
my $p = $clHash->{hmccu}{tt}{$w};
my $pn = $programName ne 'all' ? $programName : $w+1;
$s .= '<p><b>Week Program '.$pn.'</b></p><br/><table border="1">';
foreach my $d (sort keys %{$p->{ENDTIME}}) {
my $beginTime = '00:00';
$s .= '<tr><td style="padding: 2px"><b>'.$weekDay[$d].'</b></td>';
foreach my $h (sort { $a <=> $b } keys %{$p->{ENDTIME}{$d}}) {
$s .= '<td style="padding: 2px">'.$p->{ENDTIME}{$d}{$h}.' / '.$p->{TEMPERATURE}{$d}{$h}.'</td>';
$s .= '<td style="padding: 2px">'.$beginTime.' - '.$p->{ENDTIME}{$d}{$h}.': '.$p->{TEMPERATURE}{$d}{$h}.'&deg;</td>';
last if ($p->{ENDTIME}{$d}{$h} eq '24:00');
$beginTime = $p->{ENDTIME}{$d}{$h};
}
$s .= '</tr>';
}
@ -8771,6 +8686,82 @@ sub HMCCU_FormatScriptResponse ($)
return HMCCU_ISO2UTF($response);
}
######################################################################
# Login to JSON API
######################################################################
sub HMCCU_JSONLogin ($)
{
my ($hash) = @_;
my ($username, $password) = HMCCU_GetCredentials ($hash, '_json_');
return 0 if ($username eq '' || $password eq '');
my $response = HMCCU_JSONRequest ($hash, qq(
{
"method": "Session.login",
"params": {
"username": "$username",
"password": "$password"
}
}
));
return 0 if (!defined($response));
if ($response->{error} eq '') {
$hash->{hmccu}{jsonAPI}{sessionId} = $response->{result};
return 1;
}
return 0;
}
######################################################################
# Execute JSON API request
######################################################################
sub HMCCU_JSONRequest ($$)
{
my ($hash, $data) = @_;
my $ccureqtimeout = AttrVal ($hash->{NAME}, 'ccuReqTimeout', $HMCCU_TIMEOUT_REQUEST);
my ($url, $auth) = HMCCU_BuildURL ($hash, 'json');
return undef if ($url eq '');
# Blocking request
my ($err, $response) = HttpUtils_BlockingGet ({
url => $url,
method => 'POST',
timeout => $ccureqtimeout,
sslargs => {
SSL_verify_mode => 0
},
header => {
'Content-Type' => 'application/json; charset=utf-8'
},
data => $data
});
if ($err eq '') {
my $jsonResp;
my $rc = eval { $jsonResp = decode_json ($response); 1; };
if ($rc && defined($jsonResp)) {
$jsonResp->{error} //= '';
return $jsonResp;
}
else {
HMCCU_LogError ($hash, 2, "Decoding JSON response failed");
}
}
else {
HMCCU_LogError ($hash, 2, "JSON API request failed. $err");
}
return undef;
}
######################################################################
# Bulk update of reading considering attribute substexcl.
######################################################################
@ -9658,8 +9649,10 @@ sub HMCCU_BuildURL ($$)
my $authorization = $username ne '' && $password ne '' ? encode_base64 ("$username:$password", '') : '';
if ($backend eq 'rega') {
$url = $hash->{prot}."://".$hash->{host}.':'.
$HMCCU_REGA_PORT{$hash->{prot}}.'/tclrega.exe';
$url = $hash->{prot}."://".$hash->{host}.':'.$HMCCU_REGA_PORT{$hash->{prot}}.'/tclrega.exe';
}
elsif ($backend eq 'json') {
$url = $hash->{prot}."://".$hash->{host}.'/api/homematic.cgi';
}
else {
($url) = HMCCU_GetRPCServerInfo ($hash, $backend, 'url');
@ -10519,13 +10512,6 @@ sub HMCCU_GetCredentials ($@)
<li><b>get &lt;name&gt; exportdefaults &lt;filename&gt; [all]</b><br/>
Export default attributes into file. If option <i>all</i> is specified, also defaults imported
by customer will be exported.
</li><br/>
<li><b>get &lt;name&gt; firmware [{&lt;type-expr&gt; | full}]</b><br/>
Get available firmware downloads from eq-3.de. List FHEM devices with current and available
firmware version. By default only firmware version of defined HMCCUDEV or HMCCUCHN
devices are listet. With option 'full' all available firmware versions are listed.
With parameter <i>type-expr</i> one can filter displayed firmware versions by
Homematic device type.
</li><br/>
<li><b>get &lt;name&gt; internal &lt;parameter&gt;</b><br/>
Show internal values. Valid <i>parameters</i> are:<br/>

View File

@ -30,7 +30,7 @@ sub HMCCUCHN_Set ($@);
sub HMCCUCHN_Get ($@);
sub HMCCUCHN_Attr ($@);
my $HMCCUCHN_VERSION = '5.0 2024-03';
my $HMCCUCHN_VERSION = '5.0 2024-04';
######################################################################
# Initialize module

View File

@ -31,7 +31,7 @@ sub HMCCUDEV_Set ($@);
sub HMCCUDEV_Get ($@);
sub HMCCUDEV_Attr ($@);
my $HMCCUDEV_VERSION = '5.0 2024-03';
my $HMCCUDEV_VERSION = '5.0 2024-04';
######################################################################
# Initialize module

View File

@ -36,7 +36,7 @@ use SetExtensions;
######################################################################
# HMCCURPC version
my $HMCCURPCPROC_VERSION = '5.0 2024-03';
my $HMCCURPCPROC_VERSION = '5.0 2024-04';
# Maximum number of events processed per call of Read()
my $HMCCURPCPROC_MAX_EVENTS = 100;
@ -1624,6 +1624,7 @@ sub HMCCURPCPROC_StartRPCServer ($)
$hash->{hmccu}{rpc}{clkey} = $clkey;
$hash->{hmccu}{rpc}{cbport} = $callbackport;
$hash->{callback} = "$localaddr:$callbackport";
# Start RPC server process
my $rpcpid = fhemFork ();