7 Commits

Author SHA1 Message Date
8524d188d7 Add UTF-8 encoding for reading bulk updates
This commit introduces the use of the `Encode` module to ensure that
values being processed in the `WriteReadings` subroutine are correctly
encoded in UTF-8. The previous implementation did not account for
potential non-UTF-8 encoded data which could lead to issues when
updating readings.

The change specifically checks if the value (`$v`) is marked as UTF-8
using `Encode::is_utf8()`. If it is, the value is re-encoded to UTF-8
before being passed to `::readingsBulkUpdate()`. This adjustment
ensures that all data written to readings maintains proper character
encoding, improving compatibility and preventing potential data
corruption.

No breaking changes are introduced, but it is important for users
to validate that their readings correctly display any special
characters post-update.
2025-10-15 06:44:38 +02:00
7c45784c1f Update Nuki Bridge and Device to version 2.1.0
The Nuki Bridge and Device modules have been updated to version 2.1.0.
Key changes include enhancements to the command handling within the
Bridge module, replacing the `given/when` construct with a more
flexible hash-based dispatcher for clarity and maintainability.

Additionally, minor refinements have been made in the Device module,
including improved reading updates and handling of last known
device states. The experimental feature switch has been commented
out, ensuring compatibility with standard Perl versions.

These updates improve the overall robustness and readability of the
code, making it easier to maintain and extend in future versions.
No breaking changes have been introduced.
2025-10-14 10:45:26 +02:00
deeecfec7e Merge pull request 'fix: #23' (#28) from dev into main
Reviewed-on: #28
2022-09-26 12:12:58 +02:00
298bf70d93 Merge pull request 'Fix HTTP 503 Unavailable message in encode_json' (#27) from patch-useIdTagsInCommandref into dev
Reviewed-on: #27
2022-09-26 12:11:49 +02:00
a95cbbcaba Fix HTTP 503 Unavailable message in encode_json
[Ticket: none]
2022-09-26 12:07:12 +02:00
0caa0ecad3 Merge pull request 'patches-negativeTagcount' (#26) from patches-negativeTagcount into dev
Reviewed-on: #26
2021-12-17 12:44:29 +01:00
d1171bd14a fix negativ tag count in commandref 2021-12-17 12:43:44 +01:00
5 changed files with 119 additions and 107 deletions

View File

@@ -267,7 +267,7 @@ sub Initialize {
],
"release_status": "stable",
"license": "GPL_2",
"version": "v2.0.2",
"version": "v2.1.0",
"x_apiversion": "1.13.0",
"author": [
"Marko Oldenburg <leongaultier@gmail.com>"

View File

@@ -160,7 +160,6 @@ sub Initialize {
<li>disable - disables the Nuki device</li>
<br>
</ul>
</ul>
</ul>
=end html
@@ -251,7 +250,6 @@ sub Initialize {
<li>disable - disables the Nuki device</li>
<br>
</ul>
</ul>
</ul>
=end html_DE
@@ -273,7 +271,7 @@ sub Initialize {
],
"release_status": "stable",
"license": "GPL_2",
"version": "v2.0.2",
"version": "v2.1.0",
"author": [
"Marko Oldenburg <leongaultier@gmail.com>"
],

View File

@@ -1,4 +1,4 @@
UPD 2021-12-17_11:56:40 10358 FHEM/73_NUKIBridge.pm
UPD 2021-12-17_11:56:38 11116 FHEM/74_NUKIDevice.pm
UPD 2021-12-11_19:37:43 42761 lib/FHEM/Devices/Nuki/Bridge.pm
UPD 2021-12-11_19:37:43 16338 lib/FHEM/Devices/Nuki/Device.pm
UPD 2025-10-14_11:00:54 10358 FHEM/73_NUKIBridge.pm
UPD 2025-10-14_11:00:54 11100 FHEM/74_NUKIDevice.pm
UPD 2025-10-14_11:00:54 42820 lib/FHEM/Devices/Nuki/Bridge.pm
UPD 2025-10-15_06:43:51 16775 lib/FHEM/Devices/Nuki/Device.pm

View File

@@ -39,7 +39,8 @@ package FHEM::Devices::Nuki::Bridge;
use strict;
use warnings;
use experimental qw( switch );
#use experimental qw( switch );
use FHEM::Meta;
use HttpUtils;
@@ -54,7 +55,7 @@ BEGIN {
defs
modules
data
)
)
);
}
@@ -422,59 +423,59 @@ sub Set {
my $endpoint;
my $param;
$cmd = lc($cmd);
$cmd = lc $cmd;
given ($cmd) {
when ('getdevicelist') {
return 'usage: getDeviceList' if ($arg);
my %handlers = (
getdevicelist => sub {
return 'usage: getDeviceList' if $arg;
$endpoint = 'list';
}
when ('info') {
return 'usage: info' if ($arg);
},
info => sub {
return 'usage: info' if $arg;
$endpoint = 'info';
}
when ('fwupdate') {
return 'usage: fwUpdate' if ($arg);
},
fwupdate => sub {
return 'usage: fwUpdate' if $arg;
$endpoint = 'fwupdate';
}
when ('reboot') {
return 'usage: freboot' if ($arg);
},
reboot => sub {
return 'usage: reboot' if $arg;
$endpoint = 'reboot';
}
when ('clearlog') {
return 'usage: clearLog' if ($arg);
},
clearlog => sub {
return 'usage: clearLog' if $arg;
$endpoint = 'clearlog';
}
when ('factoryreset') {
return 'usage: factoryReset' if ($arg);
},
factoryreset => sub {
return 'usage: factoryReset' if $arg;
$endpoint = 'factoryreset';
}
when ('callbackremove') {
},
callbackremove => sub {
return 'usage: callbackRemove'
if ( split( m{\s+}xms, $arg ) > 1 );
my $id = ( defined($arg) ? $arg : 0 );
my $id = defined $arg ? $arg : 0;
$endpoint = 'callback/remove';
$param = '{"param":"' . $id . '"}';
}
when ('configauth') {
return 'usage: configAuth' if ( split( m{\s+}xms, $arg ) > 1 );
$endpoint = 'clearlog';
},
configauth => sub {
return 'usage: configAuth'
if ( split( m{\s+}xms, $arg ) > 1 );
my $configAuth = 'enable=' . ( $arg eq 'enable' ? 1 : 0 );
$endpoint = 'configAuth';
$param = '{"param":"' . $configAuth . '"}';
}
},
);
default {
my $list = '';
$list .= 'info:noArg getDeviceList:noArg ';
$list .=
if ( exists $handlers{$cmd} ) {
my $result = $handlers{$cmd}->();
return $result if defined $result && length $result;
}
else {
my $list = 'info:noArg getDeviceList:noArg ';
$list .=
'clearLog:noArg fwUpdate:noArg reboot:noArg factoryReset:noArg configAuth:enable,disable'
if ( ::ReadingsVal( $name, 'bridgeType', 'Software' ) eq
'Hardware' );
return ( 'Unknown argument ' . $cmd . ', choose one of ' . $list );
}
if ( ::ReadingsVal( $name, 'bridgeType', 'Software' ) eq 'Hardware' );
return "Unknown argument $cmd, choose one of $list";
}
Write( $hash, $endpoint, $param )
@@ -486,30 +487,34 @@ sub Set {
sub Get {
my $hash = shift;
my $name = shift;
my $cmd = shift // return "set $name needs at least one argument !";
my $cmd = shift // return "get $name needs at least one argument !";
my $arg = shift;
my $endpoint;
$cmd = lc($cmd);
given ($cmd) {
when ( $cmd eq 'logfile' ) {
return 'usage: logFile' if ( defined($arg) );
$endpoint = 'log';
}
when ( $cmd eq 'callbacklist' ) {
return 'usage: callbackList' if ( defined($arg) );
$endpoint = 'callback/list';
}
default {
my $list = '';
$list .= 'callbackList:noArg ';
$list .= 'logFile:noArg'
if ( ::ReadingsVal( $name, 'bridgeType', 'Software' ) eq
'Hardware' );
$cmd = lc $cmd;
return 'Unknown argument ' . $cmd . ', choose one of ' . $list;
}
my %handlers = (
logfile => sub {
return 'usage: logFile' if defined $arg;
$endpoint = 'log';
},
callbacklist => sub {
return 'usage: callbackList' if defined $arg;
$endpoint = 'callback/list';
},
);
if ( exists $handlers{$cmd} ) {
my $result = $handlers{$cmd}->();
return $result if defined $result && length $result;
}
else {
my $list = 'callbackList:noArg ';
$list .= 'logFile:noArg'
if ( ::ReadingsVal( $name, 'bridgeType', 'Software' ) eq 'Hardware' );
return "Unknown argument $cmd, choose one of $list";
}
return Write( $hash, $endpoint, undef );
@@ -750,7 +755,7 @@ sub DistributionErrHandle2 {
::asyncOutput( $param->{cl}, "Request Error: $err\r\n" )
if ( $param->{cl} && $param->{cl}{canAsyncOutput} );
return;
return $json;
}
::readingsBulkUpdate( $hash, 'lastError',
@@ -765,7 +770,7 @@ sub DistributionErrHandle2 {
::asyncOutput( $param->{cl}, "Request Error: $err\r\n" )
if ( $param->{cl} && $param->{cl}{canAsyncOutput} );
return ('received http code '
return ( 'received http code '
. $param->{code}
. ' without any data after requesting' );
}

View File

@@ -28,8 +28,9 @@ package FHEM::Devices::Nuki::Device;
use strict;
use warnings;
use experimental qw( switch );
#use experimental qw( switch );
use Encode;
use FHEM::Meta;
use GPUtils qw(GP_Import);
@@ -41,7 +42,7 @@ BEGIN {
qw( init_done
defs
modules
)
)
);
}
@@ -355,7 +356,7 @@ sub Set {
GetUpdate($hash);
return;
}
elsif ($cmd eq 'lock'
elsif ( $cmd eq 'lock'
|| lc($cmd) eq 'deactivaterto'
|| $cmd eq 'unlock'
|| lc($cmd) eq 'activaterto'
@@ -534,21 +535,23 @@ sub WriteReadings {
::readingsBeginUpdate($hash);
my $t;
my $v;
my ( $t, $v );
if ( defined( $decode_json->{lastKnownState} )
# falls lastKnownState als Hash vorliegt, direkt integrieren
if ( defined $decode_json->{lastKnownState}
&& ref( $decode_json->{lastKnownState} ) eq 'HASH' )
{
while ( ( $t, $v ) = each %{ $decode_json->{lastKnownState} } ) {
$decode_json->{$t} = $v;
}
delete $decode_json->{lastKnownState};
}
while ( ( $t, $v ) = each %{$decode_json} ) {
::readingsBulkUpdate( $hash, $t, $v )
# generische readings (alles außer spezielle Felder)
::readingsBulkUpdate( $hash, $t,
Encode::is_utf8($v) ? Encode::encode( "UTF-8", $v ) : $v )
if ( $t ne 'state'
&& $t ne 'mode'
&& $t ne 'deviceType'
@@ -560,42 +563,48 @@ sub WriteReadings {
&& $t ne 'doorsensorState'
&& $t ne 'doorsensorStateName' );
given ($t) {
when ('state') {
::readingsBulkUpdate(
$hash, $t,
(
$v =~ m{\A[0-9]\z}xms
? $lockStates{$v}->{ $hash->{DEVICETYPEID} }
: $v
)
);
}
when ('mode') {
::readingsBulkUpdate( $hash, $t,
# Dispatch-Tabelle für Spezialfälle
my %handlers = (
state => sub {
my $val =
( $v =~ m{\A[0-9]\z}xms )
? $lockStates{$v}->{ $hash->{DEVICETYPEID} }
: $v;
::readingsBulkUpdate( $hash, 'state', $val );
},
mode => sub {
::readingsBulkUpdate( $hash, 'mode',
$modes{$v}{ $hash->{DEVICETYPEID} } );
}
when ('deviceType') {
::readingsBulkUpdate( $hash, $t, $deviceTypes{$v} );
}
when ('doorsensorState') {
::readingsBulkUpdate( $hash, $t, $doorsensorStates{$v} );
}
when ('paired') {
::readingsBulkUpdate( $hash, $t,
},
devicetype => sub {
::readingsBulkUpdate( $hash, 'deviceType', $deviceTypes{$v} );
},
doorsensorstate => sub {
::readingsBulkUpdate( $hash, 'doorsensorState',
$doorsensorStates{$v} );
},
paired => sub {
::readingsBulkUpdate( $hash, 'paired',
( $v == 1 ? 'true' : 'false' ) );
}
when ('batteryCharging') {
::readingsBulkUpdate( $hash, $t,
},
batterycharging => sub {
::readingsBulkUpdate( $hash, 'batteryCharging',
( $v == 1 ? 'true' : 'false' ) );
}
when ('batteryCritical') {
},
batterycritical => sub {
::readingsBulkUpdate( $hash, 'batteryState',
( $v == 1 ? 'low' : 'ok' ) );
}
when ('batteryChargeState') {
::readingsBulkUpdate( $hash, 'batteryPercent', $v )
}
},
batterychargestate => sub {
::readingsBulkUpdate( $hash, 'batteryPercent', $v );
},
);
my $key =
lc $t; # damit Vergleiche robust gegen Groß-/Kleinschreibung sind
if ( exists $handlers{$key} ) {
$handlers{$key}->();
}
}