45 Commits
v1.9.x ... dev

Author SHA1 Message Date
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
e67ba3023e Merge pull request 'dev' (#25) from dev into main
Reviewed-on: #25
2021-12-17 12:18:11 +01:00
a8970a93e7 Merge pull request 'patch-expandCommandref' (#24) from patch-expandCommandref into dev
fixe: #7
Reviewed-on: #24
2021-12-17 12:08:50 +01:00
2f61d7c408 complete the commandref and change version for modules and minimal perl version 2021-12-17 11:57:40 +01:00
288646a882 german translation for commandref 2021-12-16 19:04:24 +01:00
247e0fef54 rewrite commandref 2021-12-16 18:17:33 +01:00
f919bab524 revision of the commandref from bridge modul 2021-12-11 19:10:53 +01:00
ae799856fe Merge pull request 'fix critical error' (#22) from patch-criticalError into dev
Reviewed-on: #22
2021-12-10 22:00:55 +01:00
168c29f444 fix critical error 2021-12-10 21:59:48 +01:00
ca58793d03 Merge pull request 'patch-improvementErrorHandling' (#21) from patch-improvementErrorHandling into dev
Reviewed-on: #21
2021-12-10 20:46:36 +01:00
6b75e5c9dc make all modules perlcritic level3 conform 2021-12-10 20:24:31 +01:00
f1418ca195 rewrite code perlcritic level3 conform 2021-12-10 13:27:53 +01:00
5864a56b40 Merge pull request 'Version 2.0 Pre-Release' (#20) from devel into main
Reviewed-on: #20
2021-12-05 12:25:37 +01:00
326f49dd15 Merge pull request 'change GetCallBridgeAlive Endpoint because of a bug' (#19) from patch-endpointBug into devel
Reviewed-on: #19
2021-12-05 12:17:47 +01:00
bac765ac85 change GetCallBridgeAlive Endpoint because of a bug
https://developer.nuki.io/t/support-for-new-smart-lock-3-0-3-0-pro/12842/12?u=leongaultier
2021-12-05 12:14:50 +01:00
f7ad606603 Merge pull request 'add README.md' (#18) from patch-implemntationAllModelAndFunctions into devel
Reviewed-on: #18
2021-11-30 10:04:48 +01:00
f86aa29419 add README.md 2021-11-30 10:02:49 +01:00
c1d1a5a68c Merge pull request 'fix Undefined subroutine &FHEM::Devices::Nuki::Bridge::Log3' (#17) from patch-criticalBug into devel
Reviewed-on: #17
2021-11-28 16:51:35 +01:00
269da4d4f2 fix Undefined subroutine &FHEM::Devices::Nuki::Bridge::Log3 2021-11-28 16:48:15 +01:00
7816ab3119 Merge pull request 'patch-discoveryAuthorization' (#14) from patch-discoveryAuthorization into devel
Reviewed-on: #14
2021-11-28 07:32:15 +01:00
99fcb221d8 fix little bugs 2021-11-28 00:31:39 +01:00
4489744f90 add configAuth option enable/disable publication of the local IP and
port via discovery URL
2021-11-27 23:34:28 +01:00
1b001e942a Merge pull request 'fix little model bugs' (#12) from patch-discoveryAuthorization into devel
Reviewed-on: #12
2021-11-27 23:00:20 +01:00
efbea2f987 Merge branch 'patch-implemntationAllModelAndFunctions' into patch-discoveryAuthorization 2021-11-27 22:57:15 +01:00
25a682224b change model and fix problems 2021-11-27 22:51:25 +01:00
e87f03fe63 Merge branch 'devel' into patch-discoveryAuthorization 2021-11-27 21:38:11 +01:00
de2ecf664f Merge pull request 'change model name for smartlock 3.0 api conform. fix little bugs' (#10) from patch-changeModel into devel
Reviewed-on: #10
2021-11-27 21:35:05 +01:00
05e5322b42 change model name for smartlock 3.0 api conform. fix little bugs 2021-11-27 21:32:19 +01:00
e634cf4437 code clean and new battery readings 2021-11-27 18:45:00 +01:00
681e944b44 Merge pull request 'patch-discoveryAPIactivation' (#8) from patch-discoveryAPIactivation into devel
Reviewed-on: #8
2021-11-27 18:22:22 +01:00
a8ea6814ab add discovery and full automation define bridge with host and port from
fetch API information via /auth endpoint
2021-11-27 18:08:27 +01:00
c21bd2479a fix uninitialized value $iodev in hash element line 221 2021-11-27 09:52:55 +01:00
5b268a4d9c Merge pull request 'patch-newModulStructure' (#3) from patch-newModulStructure into devel
Reviewed-on: #3
2021-11-26 19:47:17 +01:00
3755e1b236 add support für fhem update command 2021-11-26 19:45:29 +01:00
4694030cd5 ready for testing 2021-11-26 19:38:49 +01:00
1bc18d3263 add wlanConnected reading 2021-11-26 11:49:43 +01:00
980c105268 Merge branch 'devel' into patch-newModulStructure 2021-11-26 10:30:27 +01:00
897105af79 add support for Nuki 3.0 SmartLock 2021-11-26 09:47:31 +01:00
a612cdf1e4 change code of Initialize to FHEM::NUKIBridge for Meta Support 2021-11-26 08:11:16 +01:00
a38d120a28 fix little bugs 2021-11-25 22:53:20 +01:00
a4eef36061 remove commandref from new package file Bridge.pm and insert new API
document
2021-11-25 22:10:58 +01:00
d9b47b4228 code rewrite for packages and new modul directory structure 2021-11-25 21:56:00 +01:00
12 changed files with 2781 additions and 2264 deletions

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -1,800 +0,0 @@
###############################################################################
#
# Developed with Kate
#
# (c) 2016-2021 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net)
# All rights reserved
#
# This script 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 2 of the License, or
# any later version.
#
# The GNU General Public License can be found at
# http://www.gnu.org/copyleft/gpl.html.
# A copy is found in the textfile GPL.txt and important notices to the license
# from the author is found in LICENSE.txt distributed with these scripts.
#
# This script 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.
#
#
# $Id$
#
###############################################################################
package main;
use strict;
use warnings;
package FHEM::NUKIDevice;
use strict;
use warnings;
use FHEM::Meta;
use GPUtils qw(GP_Import GP_Export);
main::LoadModule('NUKIBridge');
# try to use JSON::MaybeXS wrapper
# for chance of better performance + open code
eval {
require JSON::MaybeXS;
import JSON::MaybeXS qw( decode_json encode_json );
1;
};
if ($@) {
$@ = undef;
# try to use JSON wrapper
# for chance of better performance
eval {
# JSON preference order
local $ENV{PERL_JSON_BACKEND} =
'Cpanel::JSON::XS,JSON::XS,JSON::PP,JSON::backportPP'
unless ( defined( $ENV{PERL_JSON_BACKEND} ) );
require JSON;
import JSON qw( decode_json encode_json );
1;
};
if ($@) {
$@ = undef;
# In rare cases, Cpanel::JSON::XS may
# be installed but JSON|JSON::MaybeXS not ...
eval {
require Cpanel::JSON::XS;
import Cpanel::JSON::XS qw(decode_json encode_json);
1;
};
if ($@) {
$@ = undef;
# In rare cases, JSON::XS may
# be installed but JSON not ...
eval {
require JSON::XS;
import JSON::XS qw(decode_json encode_json);
1;
};
if ($@) {
$@ = undef;
# Fallback to built-in JSON which SHOULD
# be available since 5.014 ...
eval {
require JSON::PP;
import JSON::PP qw(decode_json encode_json);
1;
};
if ($@) {
$@ = undef;
# Fallback to JSON::backportPP in really rare cases
require JSON::backportPP;
import JSON::backportPP qw(decode_json encode_json);
1;
}
}
}
}
}
## Import der FHEM Funktionen
#-- Run before package compilation
BEGIN {
# Import from main context
GP_Import(
qw(
readingsSingleUpdate
readingsBulkUpdate
readingsBeginUpdate
readingsEndUpdate
readingFnAttributes
makeDeviceName
defs
modules
Log3
CommandAttr
AttrVal
IsDisabled
deviceEvents
init_done
InternalVal
ReadingsVal
AssignIoPort
IOWrite
data)
);
}
#-- Export to main context with different name
GP_Export(
qw(
Initialize
)
);
my %deviceTypes = (
0 => 'smartlock',
2 => 'opener',
4 => 'smartlockNG'
);
my %modes = (
2 => {
0 => 'door mode',
2 => 'door mode'
},
3 => {
0 => '-',
2 => ' continuous mode'
}
);
my %lockStates = (
0 => {
0 => 'uncalibrated',
2 => 'untrained',
4 => 'uncalibrated'
},
1 => {
0 => 'locked',
2 => 'online',
4 => 'locked'
},
2 => {
0 => 'unlocking',
2 => '-',
4 => 'unlocking'
},
3 => {
0 => 'unlocked',
2 => 'rto active',
4 => 'unlocked'
},
4 => {
0 => 'locking',
2 => '-',
4 => 'locking'
},
5 => {
0 => 'unlatched',
2 => 'open',
4 => 'unlatched'
},
6 => {
0 => 'unlocked (lock n go)',
2 => '-',
4 => 'unlocked (lock n go)'
},
7 => {
0 => 'unlatching',
2 => 'opening',
4 => 'unlatching'
},
253 => {
0 => '-',
2 => 'boot run',
4 => '-'
},
254 => {
0 => 'motor blocked',
2 => '-',
4 => 'motor blocked'
},
255 => {
0 => 'undefined',
2 => 'undefined',
4 => 'undefined'
}
);
my %deviceTypeIds = reverse(%deviceTypes);
sub Initialize($) {
my ($hash) = @_;
$hash->{Match} = '^{.*}$';
$hash->{SetFn} = 'FHEM::NUKIDevice::Set';
$hash->{DefFn} = 'FHEM::NUKIDevice::Define';
$hash->{UndefFn} = 'FHEM::NUKIDevice::Undef';
$hash->{NotifyFn} = 'FHEM::NUKIDevice::Notify';
$hash->{AttrFn} = 'FHEM::NUKIDevice::Attr';
$hash->{ParseFn} = 'FHEM::NUKIDevice::Parse';
$hash->{AttrList} =
'IODev '
. 'model:opener,smartlock '
. 'disable:1 '
. $readingFnAttributes;
return FHEM::Meta::InitMod( __FILE__, $hash );
}
sub Define($$) {
my ( $hash, $def ) = @_;
my @a = split( '[ \t][ \t]*', $def );
return $@ unless ( FHEM::Meta::SetInternals($hash) );
use version 0.60; our $VERSION = FHEM::Meta::Get( $hash, 'version' );
return 'too few parameters: define <name> NUKIDevice <nukiId> <deviceType>'
if ( @a != 4 );
my $name = $a[0];
my $nukiId = $a[2];
my $deviceType = ( defined $a[3] ) ? $a[3] : 0;
$hash->{NUKIID} = $nukiId;
$hash->{DEVICETYPE} = ( defined $deviceType ) ? $deviceType : 0;
$hash->{VERSION} = version->parse($VERSION)->normal;
$hash->{STATE} = 'Initialized';
$hash->{NOTIFYDEV} = 'global,autocreate,' . $name;
my $iodev = AttrVal( $name, 'IODev', 'none' );
AssignIoPort( $hash, $iodev ) if ( !$hash->{IODev} );
if ( defined( $hash->{IODev}->{NAME} ) ) {
Log3( $name, 3,
"NUKIDevice ($name) - I/O device is " . $hash->{IODev}->{NAME} );
}
else {
Log3( $name, 1, "NUKIDevice ($name) - no I/O device" );
}
$iodev = $hash->{IODev}->{NAME};
$hash->{BRIDGEAPI} = $defs{$iodev}->{BRIDGEAPI};
my $d = $modules{NUKIDevice}{defptr}{$nukiId};
return
'NUKIDevice device '
. $name
. ' on NUKIBridge '
. $iodev
. ' already defined.'
if ( defined($d)
and $d->{IODev} == $hash->{IODev}
and $d->{NAME} ne $name );
Log3( $name, 3, "NUKIDevice ($name) - defined with NukiId: $nukiId" );
CommandAttr( undef, $name . ' room NUKI' )
if ( AttrVal( $name, 'room', 'none' ) eq 'none' );
CommandAttr( undef, $name . ' model ' . $deviceTypes{$deviceType} )
if ( AttrVal( $name, 'model', 'none' ) eq 'none' );
$modules{NUKIDevice}{defptr}{$nukiId} = $hash;
GetUpdate($hash)
if ( ReadingsVal( $name, 'success', 'none' ) eq 'none'
and $init_done );
return undef;
}
sub Undef($$) {
my ( $hash, $arg ) = @_;
my $nukiId = $hash->{NUKIID};
my $name = $hash->{NAME};
Log3( $name, 3, "NUKIDevice ($name) - undefined with NukiId: $nukiId" );
delete( $modules{NUKIDevice}{defptr}{$nukiId} );
return undef;
}
sub Attr(@) {
my ( $cmd, $name, $attrName, $attrVal ) = @_;
my $hash = $defs{$name};
my $token = $hash->{IODev}->{TOKEN};
if ( $attrName eq 'disable' ) {
if ( $cmd eq 'set' and $attrVal == 1 ) {
readingsSingleUpdate( $hash, 'state', 'disabled', 1 );
Log3( $name, 3, "NUKIDevice ($name) - disabled" );
}
elsif ( $cmd eq 'del' ) {
readingsSingleUpdate( $hash, 'state', 'active', 1 );
Log3( $name, 3, "NUKIDevice ($name) - enabled" );
}
}
elsif ( $attrName eq 'disabledForIntervals' ) {
if ( $cmd eq 'set' ) {
Log3( $name, 3,
"NUKIDevice ($name) - enable disabledForIntervals" );
readingsSingleUpdate( $hash, 'state', 'Unknown', 1 );
}
elsif ( $cmd eq 'del' ) {
readingsSingleUpdate( $hash, 'state', 'active', 1 );
Log3( $name, 3,
"NUKIDevice ($name) - delete disabledForIntervals" );
}
}
elsif ( $attrName eq 'model' ) {
if ( $cmd eq 'set' ) {
Log3( $name, 3, "NUKIDevice ($name) - change model" );
$hash->{DEVICETYPE} = $deviceTypeIds{$attrVal};
}
}
return undef;
}
sub Notify($$) {
my ( $hash, $dev ) = @_;
my $name = $hash->{NAME};
return if ( IsDisabled($name) );
my $devname = $dev->{NAME};
my $devtype = $dev->{TYPE};
my $events = deviceEvents( $dev, 1 );
return if ( !$events );
GetUpdate($hash)
if (
(
grep /^INITIALIZED$/,
@{$events}
or grep /^REREADCFG$/,
@{$events}
or grep /^MODIFIED.$name$/,
@{$events}
or grep /^DEFINED.$name$/,
@{$events}
)
and $devname eq 'global'
and $init_done
);
return;
}
sub Set($$@) {
my ( $hash, $name, @aa ) = @_;
my ( $cmd, @args ) = @aa;
my $lockAction;
if ( lc($cmd) eq 'statusrequest' ) {
return ('usage: statusRequest') if ( @args != 0 );
GetUpdate($hash);
return undef;
}
elsif ($cmd eq 'lock'
or lc($cmd) eq 'deactivaterto'
or $cmd eq 'unlock'
or lc($cmd) eq 'activaterto'
or $cmd eq 'unlatch'
or lc($cmd) eq 'electricstrikeactuation'
or lc($cmd) eq 'lockngo'
or lc($cmd) eq 'activatecontinuousmode'
or lc($cmd) eq 'lockngowithunlatch'
or lc($cmd) eq 'deactivatecontinuousmode'
or $cmd eq 'unpair' )
{
return ( 'usage: ' . $cmd )
if ( @args != 0 );
$lockAction = $cmd;
}
else {
my $list = '';
$list =
'statusRequest:noArg unlock:noArg lock:noArg unlatch:noArg locknGo:noArg locknGoWithUnlatch:noArg unpair:noArg'
if ( $hash->{DEVICETYPE} == 0
|| $hash->{DEVICETYPE} == 4 );
$list =
'statusRequest:noArg activateRto:noArg deactivateRto:noArg electricStrikeActuation:noArg activateContinuousMode:noArg deactivateContinuousMode:noArg unpair:noArg'
if ( $hash->{DEVICETYPE} == 2 );
return ( 'Unknown argument ' . $cmd . ', choose one of ' . $list );
}
$hash->{helper}{lockAction} = $lockAction;
# IOWrite( $hash, 'lockAction', $lockAction, $hash->{NUKIID},
# $hash->{DEVICETYPE} );
IOWrite( $hash, 'lockAction', '{"param":"' . $lockAction
. '","nukiId":' . $hash->{NUKIID} . ',"deviceType":' . $hash->{DEVICETYPE} . '}' );
return undef;
}
sub GetUpdate($) {
my $hash = shift;
my $name = $hash->{NAME};
if ( !IsDisabled($name) ) {
# IOWrite( $hash, 'lockState', undef, $hash->{NUKIID},
# $hash->{DEVICETYPE} );
IOWrite( $hash, 'lockState', '{"nukiId":' . $hash->{NUKIID}
. ',"deviceType":' . $hash->{DEVICETYPE} . '}' );
Log3( $name, 2, "NUKIDevice ($name) - GetUpdate Call IOWrite" );
}
return undef;
}
sub Parse($$) {
my ( $hash, $json ) = @_;
my $name = $hash->{NAME};
Log3( $name, 5, "NUKIDevice ($name) - Parse with result: $json" );
#########################################
####### Errorhandling #############
if ( $json !~ m/^[\[{].*[}\]]$/ ) {
Log3( $name, 3, "NUKIDevice ($name) - invalid json detected: $json" );
return "NUKIDevice ($name) - invalid json detected: $json";
}
#########################################
#### verarbeiten des JSON Strings #######
my $decode_json = eval { decode_json($json) };
if ($@) {
Log3( $name, 3, "NUKIDevice ($name) - JSON error while request: $@" );
return;
}
if ( ref($decode_json) ne 'HASH' ) {
Log3( $name, 2,
"NUKIDevice ($name) - got wrong status message for $name: $decode_json"
);
return undef;
}
my $nukiId = $decode_json->{nukiId};
if ( my $hash = $modules{NUKIDevice}{defptr}{$nukiId} ) {
my $name = $hash->{NAME};
WriteReadings( $hash, $decode_json );
Log3( $name, 4,
"NUKIDevice ($name) - find logical device: $hash->{NAME}" );
##################
## Zwischenlösung so für die Umstellung, kann später gelöscht werden
if ( AttrVal( $name, 'model', '' ) eq '' ) {
CommandDefMod( undef,
$name
. ' NUKIDevice '
. $hash->{NUKIID} . ' '
. $decode_json->{deviceType} );
CommandAttr( undef,
$name
. ' model '
. $deviceTypes{ $decode_json->{deviceType} } );
Log3( $name, 2, "NUKIDevice ($name) - redefined Defmod" );
}
return $hash->{NAME};
}
else {
Log3( $name, 4,
"NUKIDevice ($name) - autocreate new device "
. makeDeviceName( $decode_json->{name} )
. " with nukiId $decode_json->{nukiId}, model $decode_json->{deviceType}"
);
return
'UNDEFINED '
. makeDeviceName( $decode_json->{name} )
. " NUKIDevice $decode_json->{nukiId} $decode_json->{deviceType}";
}
Log3( $name, 5, "NUKIDevice ($name) - parse status message for $name" );
WriteReadings( $hash, $decode_json );
}
sub WriteReadings($$) {
my ( $hash, $decode_json ) = @_;
my $name = $hash->{NAME};
############################
#### Status des Smartlock
if ( defined( $hash->{helper}{lockAction} ) ) {
my $state;
if (
defined( $decode_json->{success} )
and ( $decode_json->{success} eq 'true'
or $decode_json->{success} == 1 )
)
{
$state = $hash->{helper}{lockAction};
# IOWrite( $hash, 'lockState', undef, $hash->{NUKIID} )
IOWrite( $hash, 'lockState', '{"nukiId":' . $hash->{NUKIID}
. ',"deviceType":' . $hash->{DEVICETYPE} . '}' )
if (
ReadingsVal( $hash->{IODev}->{NAME}, 'bridgeType', 'Software' )
eq 'Software' );
}
elsif (
defined( $decode_json->{success} )
and ( $decode_json->{success} eq 'false'
or $decode_json->{success} == 0 )
)
{
$state = $deviceTypes{ $hash->{DEVICETYPE} } . ' response error';
# IOWrite( $hash, 'lockState', undef, $hash->{NUKIID},
# $hash->{DEVICETYPE} );
IOWrite( $hash, 'lockState', '{"nukiId":' . $hash->{NUKIID}
. ',"deviceType":' . $hash->{DEVICETYPE} . '}' );
}
$decode_json->{'state'} = $state;
delete $hash->{helper}{lockAction};
}
readingsBeginUpdate($hash);
my $t;
my $v;
if ( defined( $decode_json->{lastKnownState} )
and 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 )
unless ( $t eq 'state'
or $t eq 'mode'
or $t eq 'deviceType'
or $t eq 'paired'
or $t eq 'batteryCritical'
or $t eq 'timestamp' );
readingsBulkUpdate( $hash, $t,
( $v =~ m/^[0-9]$/ ? $lockStates{$v}{ $hash->{DEVICETYPE} } : $v ) )
if ( $t eq 'state' );
readingsBulkUpdate( $hash, $t, $modes{$v}{ $hash->{DEVICETYPE} } )
if ( $t eq 'mode' );
readingsBulkUpdate( $hash, $t, $deviceTypes{$v} )
if ( $t eq 'deviceType' );
readingsBulkUpdate( $hash, $t, ( $v == 1 ? 'true' : 'false' ) )
if ( $t eq 'paired' );
readingsBulkUpdate( $hash, 'batteryState',
( ( $v eq 'true' or $v == 1 ) ? 'low' : 'ok' ) )
if ( $t eq 'batteryCritical' );
}
readingsEndUpdate( $hash, 1 );
Log3( $name, 5, "NUKIDevice ($name) - lockAction readings set for $name" );
return undef;
}
1;
=pod
=item device
=item summary Modul to control the Nuki Smartlock's
=item summary_DE Modul zur Steuerung des Nuki Smartlocks.
=begin html
<a name="NUKIDevice"></a>
<h3>NUKIDevice</h3>
<ul>
<u><b>NUKIDevice - Controls the Nuki Smartlock</b></u>
<br>
The Nuki module connects FHEM over the Nuki Bridge with a Nuki Smartlock or Nuki Opener. After that, it´s possible to lock and unlock the Smartlock.<br>
Normally the Nuki devices are automatically created by the bridge module.
<br><br>
<a name="NUKIDevicedefine"></a>
<b>Define</b>
<ul><br>
<code>define &lt;name&gt; NUKIDevice &lt;Nuki-Id&gt; &lt;IODev-Device&gt; &lt;Device-Type&gt;</code>
<br><br>
Device-Type is 0 for the Smartlock and 2 for the Opener.
<br><br>
Example:
<ul><br>
<code>define Frontdoor NUKIDevice 1 NBridge1 0</code><br>
</ul>
<br>
This statement creates a NUKIDevice with the name Frontdoor, the NukiId 1 and the IODev device NBridge1.<br>
After the device has been created, the current state of the Smartlock is automatically read from the bridge.
</ul>
<br><br>
<a name="NUKIDevicereadings"></a>
<b>Readings</b>
<ul>
<li>state - Status of the Smartlock or error message if any error.</li>
<li>lockState - current lock status uncalibrated, locked, unlocked, unlocked (lock n go), unlatched, locking, unlocking, unlatching, motor blocked, undefined.</li>
<li>name - name of the device</li>
<li>paired - paired information false/true</li>
<li>rssi - value of rssi</li>
<li>succes - true, false Returns the status of the last closing command. Ok or not Ok.</li>
<li>batteryCritical - Is the battery in a critical state? True, false</li>
<li>batteryState - battery status, ok / low</li>
</ul>
<br><br>
<a name="NUKIDeviceset"></a>
<b>Set</b>
<ul>
<li>statusRequest - retrieves the current state of the smartlock from the bridge.</li>
<li>lock - lock</li>
<li>unlock - unlock</li>
<li>unlatch - unlock / open Door</li>
<li>unpair - Removes the pairing with a given Smart Lock</li>
<li>locknGo - lock when gone</li>
<li>locknGoWithUnlatch - lock after the door has been opened</li>
<br>
</ul>
<br><br>
<a name="NUKIDeviceattribut"></a>
<b>Attributes</b>
<ul>
<li>disable - disables the Nuki device</li>
<br>
</ul>
</ul>
=end html
=begin html_DE
<a name="NUKIDevice"></a>
<h3>NUKIDevice</h3>
<ul>
<u><b>NUKIDevice - Steuert das Nuki Smartlock</b></u>
<br>
Das Nuki Modul verbindet FHEM über die Nuki Bridge mit einem Nuki Smartlock oder Nuki Opener. Es ist dann m&ouml;glich das Schloss zu ver- und entriegeln.<br>
In der Regel werden die Nuki Devices automatisch durch das Bridgemodul angelegt.
<br><br>
<a name="NUKIDevicedefine"></a>
<b>Define</b>
<ul><br>
<code>define &lt;name&gt; NUKIDevice &lt;Nuki-Id&gt; &lt;IODev-Device&gt; &lt;Device-Type&gt;</code>
<br><br>
Device-Type ist 0 f&uuml;r das Smartlock und 2 f&üuml;r den Opener.
<br><br>
Beispiel:
<ul><br>
<code>define Haust&uuml;r NUKIDevice 1 NBridge1 0</code><br>
</ul>
<br>
Diese Anweisung erstellt ein NUKIDevice mit Namen Haust&uuml;r, der NukiId 1 sowie dem IODev Device NBridge1.<br>
Nach dem anlegen des Devices wird automatisch der aktuelle Zustand des Smartlocks aus der Bridge gelesen.
</ul>
<br><br>
<a name="NUKIDevicereadings"></a>
<b>Readings</b>
<ul>
<li>state - Status des Smartlock bzw. Fehlermeldung von Fehler vorhanden.</li>
<li>lockState - aktueller Schlie&szlig;status uncalibrated, locked, unlocked, unlocked (lock n go), unlatched, locking, unlocking, unlatching, motor blocked, undefined.</li>
<li>name - Name des Smart Locks</li>
<li>paired - pairing Status des Smart Locks</li>
<li>rssi - rssi Wert des Smart Locks</li>
<li>succes - true, false Gibt des Status des letzten Schlie&szlig;befehles wieder. Geklappt oder nicht geklappt.</li>
<li>batteryCritical - Ist die Batterie in einem kritischen Zustand? true, false</li>
<li>batteryState - Status der Batterie, ok/low</li>
</ul>
<br><br>
<a name="NUKIDeviceset"></a>
<b>Set</b>
<ul>
<li>statusRequest - ruft den aktuellen Status des Smartlocks von der Bridge ab.</li>
<li>lock - verschlie&szlig;en</li>
<li>unlock - aufschlie&szlig;en</li>
<li>unlatch - entriegeln/Falle &ouml;ffnen.</li>
<li>unpair - entfernt das pairing mit dem Smart Lock</li>
<li>locknGo - verschlie&szlig;en wenn gegangen</li>
<li>locknGoWithUnlatch - verschlie&szlig;en nach dem die Falle ge&ouml;ffnet wurde.</li>
<br>
</ul>
<br><br>
<a name="NUKIDeviceattribut"></a>
<b>Attribute</b>
<ul>
<li>disable - deaktiviert das Nuki Device</li>
<br>
</ul>
</ul>
=end html_DE
=for :application/json;q=META.json 74_NUKIDevice.pm
{
"abstract": "Modul to control the Nuki Smartlock's over the Nuki Bridge",
"x_lang": {
"de": {
"abstract": "Modul to control the Nuki Smartlock's over the Nuki Bridge"
}
},
"keywords": [
"fhem-mod-device",
"fhem-core",
"Smartlock",
"Nuki",
"Control"
],
"release_status": "stable",
"license": "GPL_2",
"version": "v1.9.50",
"author": [
"Marko Oldenburg <leongaultier@gmail.com>"
],
"x_fhem_maintainer": [
"CoolTux"
],
"x_fhem_maintainer_github": [
"LeonGaultier"
],
"prereqs": {
"runtime": {
"requires": {
"FHEM": 5.00918799,
"perl": 5.016,
"Meta": 0,
"JSON": 0,
"Date::Parse": 0
},
"recommends": {
},
"suggests": {
}
}
}
}
=end :application/json;q=META.json
=cut

Binary file not shown.

Binary file not shown.

299
FHEM/73_NUKIBridge.pm Normal file
View File

@ -0,0 +1,299 @@
###############################################################################
#
# Developed with VSCodium and richterger perl plugin
#
# (c) 2016-2021 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net)
# All rights reserved
#
# This script 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 2 of the License, or
# any later version.
#
# The GNU General Public License can be found at
# http://www.gnu.org/copyleft/gpl.html.
# A copy is found in the textfile GPL.txt and important notices to the license
# from the author is found in LICENSE.txt distributed with these scripts.
#
# This script 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.
#
#
# $Id$
#
###############################################################################
#################################
######### Wichtige Hinweise und Links #################
## Beispiel für Logausgabe
# https://forum.fhem.de/index.php/topic,55756.msg508412.html#msg508412
##
#
################################
package FHEM::NUKIBridge;
use strict;
use warnings;
use FHEM::Meta;
require FHEM::Devices::Nuki::Bridge;
use GPUtils qw(GP_Import);
BEGIN {
# Import from main context
GP_Import(qw( readingFnAttributes ));
}
sub ::NUKIBridge_Initialize { goto &Initialize }
sub Initialize {
my ($hash) = @_;
# Provider
$hash->{WriteFn} = \&FHEM::Devices::Nuki::Bridge::Write;
$hash->{Clients} = ':NUKIDevice:';
$hash->{MatchList} = { '1:NUKIDevice' => '^{.*}$' };
my $webhookFWinstance =
join( ",", ::devspec2array('TYPE=FHEMWEB:FILTER=TEMPORARY!=1') );
# Consumer
$hash->{SetFn} = \&FHEM::Devices::Nuki::Bridge::Set;
$hash->{GetFn} = \&FHEM::Devices::Nuki::Bridge::Get;
$hash->{DefFn} = \&FHEM::Devices::Nuki::Bridge::Define;
$hash->{UndefFn} = \&FHEM::Devices::Nuki::Bridge::Undef;
$hash->{NotifyFn} = \&FHEM::Devices::Nuki::Bridge::Notify;
$hash->{AttrFn} = \&FHEM::Devices::Nuki::Bridge::Attr;
$hash->{AttrList} =
'disable:1 ' . 'port '
. 'webhookFWinstance:'
. $webhookFWinstance . ' '
. 'webhookHttpHostname '
. $readingFnAttributes;
return FHEM::Meta::InitMod( __FILE__, $hash );
}
1;
=pod
=item device
=item summary Modul to control the Nuki Smartlock's over the Nuki Bridge.
=item summary_DE Modul zur Steuerung des Nuki Smartlock über die Nuki Bridge.
=begin html
<a name="NUKIBridge"></a>
<h3>NUKIBridge</h3>
<ul>
<u><b>NUKIBridge - controls Nuki Devices (Smartlock, Opener and so on) over the Nuki Bridge</b></u>
<br>
The Nuki Bridge module connects FHEM to the Nuki Bridge and then reads all the Nuki devices available on the bridge. Furthermore, the detected Nuki smart devices are automatically created as independent devices.
<br><br>
<a name="NUKIBridgedefine"></a>
<b>Define</b><br>
There a two ways to define the bridge for use in fhem.<br>
<b>first:</b>
<ul>
<code>define &lt;name&gt; NUKIBridge</code>
<br><br>
Example:
<ul><br>
<code>define NBridge1 NUKIBridge</code><br>
</ul>
<br>
This statement creates a NUKIBridge device and activated the Bridge discovery and API activation. Once a bridge has been discovered on the LAN the API done be activated and the API token retrieved. You has to confirm this request by pressing the button on the bridge.<br>
After the bridge device is setting up, all available Smartlocks are automatically placed in FHEM.
</ul><br>
<b>second:</b>
<ul>
<code>define &lt;name&gt; NUKIBridge &lt;HOST&gt; &lt;API-TOKEN&gt;</code>
<br><br>
Example:
<ul><br>
<code>define NBridge1 NUKIBridge 192.168.0.23 F34HK6</code><br>
</ul>
<br>
This statement creates a NUKIBridge device with the name NBridge1 and the IP 192.168.0.23 as well as the token F34HK6.<br>
After the bridge device is created, all available Smartlocks are automatically placed in FHEM.
</ul>
<br><br>
<a name="NUKIBridgereadings"></a>
<b>Readings</b>
<ul>
<li>bridgeType - Hardware bridge / Software bridge</li>
<li>configAuthSuccess - state of command activat/deactiviate bridge discovery</li>
<li>currentGMTime - Current timestamp</li>
<li>firmwareVersion - Version of the bridge firmware</li>
<li>hardwareId - Hardware ID</li>
<li>lastError - Last connected error</li>
<li>serverConnected - Flag indicating whether or not the bridge is connected to the Nuki server</li>
<li>serverId - Server ID</li>
<li>state - state of the bridge device, mostly online</li>
<li>uptime - Uptime of the bridge in seconds</li>
<li>wifiFirmwareVersion- Version of the WiFi modules firmware</li>
<li>wlanConnected - wifi connect?</li>
<br>
The preceding number is continuous, starts with 0 und returns the properties of <b>one</b> Smartlock.
</ul>
<br><br>
<a name="NUKIBridgeset"></a>
<b>Set</b>
<ul>
<li>getDeviceList - Prompts to re-read all devices from the bridge and if not already present in FHEM, create the automatically.</li>
<li>callbackRemove - Removes a previously added callback</li>
<li>clearLog - Clears the log of the Bridge (only hardwarebridge)</li>
<li>factoryReset - Performs a factory reset (only hardwarebridge)</li>
<li>fwUpdate - Immediately checks for a new firmware update and installs it (only hardwarebridge)</li>
<li>info - Returns all Smart Locks in range and some device information of the bridge itself</li>
<li>reboot - reboots the bridge (only hardwarebridge)</li>
<br>
</ul>
<br><br>
<a name="NUKIBridgeget"></a>
<b>Get</b>
<ul>
<li>callbackList - List of register url callbacks.</li>
<li>logFile - Retrieves the log of the Bridge</li>
<br>
</ul>
<br><br>
<a name="NUKIBridgeattribut"></a>
<b>Attributes</b>
<ul>
<li>disable - disables the Nuki Bridge</li>
<li>webhookFWinstance - Webinstanz of the Callback</li>
<li>webhookHttpHostname - IP or FQDN of the FHEM Server Callback</li>
<br>
</ul>
</ul>
=end html
=begin html_DE
<a name="NUKIBridge"></a>
<h3>NUKIBridge</h3>
<ul>
<u><b>NUKIBridge - Steuert das Nuki Smartlock über die Nuki Bridge</b></u>
<br>
Das Nuki Bridge Modul verbindet FHEM mit der Nuki Bridge und liest dann alle auf der Bridge verf&uuml;gbaren Smartlocks ein. Desweiteren werden automatisch die erkannten Smartlocks als eigenst&auml;ndige Devices an gelegt.
<br><br>
<a name="NUKIBridgedefine"></a>
<b>Define</b>
<ul><br>
<code>define &lt;name&gt; NUKIBridge &lt;HOST&gt; &lt;API-TOKEN&gt;</code>
<br><br>
Beispiel:
<ul><br>
<code>define NBridge1 NUKIBridge 192.168.0.23 F34HK6</code><br>
</ul>
<br>
Diese Anweisung erstellt ein NUKIBridge Device mit Namen NBridge1 und der IP 192.168.0.23 sowie dem Token F34HK6.<br>
Nach dem anlegen des Bridge Devices werden alle zur verf&uuml;gung stehende Smartlock automatisch in FHEM an gelegt.
</ul>
<br><br>
<a name="NUKIBridgereadings"></a>
<b>Readings</b>
<ul>
<li>bridgeType - Hardware oder Software/App Bridge</li>
<li>configAuthSuccess - status des Kommandos zum aktivieren/deaktivieren des bridge discovery</li>
<li>currentGMTime - aktuelle Zeit auf der Bridge zum zeitpunkt des Info holens</li>
<li>firmwareVersion - aktuell auf der Bridge verwendete Firmwareversion</li>
<li>hardwareId - ID der Hardware Bridge</li>
<li>lastError - gibt die letzte HTTP Errormeldung wieder</li>
<li>serverConnected - true/false gibt an ob die Hardwarebridge Verbindung zur Nuki-Cloude hat.</li>
<li>serverId - gibt die ID des Cloudeservers wieder</li>
<li>state - status der bridge zu fhem, zu meist online :-)</li>
<li>uptime - Uptime der Bridge in Sekunden</li>
<li>wifiFirmwareVersion- Firmwareversion des Wifi Modules der Bridge</li>
<li>wlanConnected - Wlan verbunden?</li>
<br>
Die vorangestellte Zahl ist forlaufend und gibt beginnend bei 0 die Eigenschaften <b>Eines</b> Smartlocks wieder.
</ul>
<br><br>
<a name="NUKIBridgeset"></a>
<b>Set</b>
<ul>
<li>getDeviceList - Veranlasst ein erneutes Einlesen aller Devices von der Bridge und falls noch nicht in FHEM vorhanden das automatische anlegen.</li>
<li>callbackRemove - L&ouml;schen der Callback Instanz auf der Bridge.</li>
<li>clearLog - l&ouml;scht das Logfile auf der Bridge</li>
<li>fwUpdate - schaut nach einer neueren Firmware und installiert diese sofern vorhanden</li>
<li>info - holt aktuellen Informationen &uuml;ber die Bridge</li>
<li>reboot - veranl&auml;sst ein reboot der Bridge</li>
<br>
</ul>
<br><br>
<a name="NUKIBridgeget"></a>
<b>Get</b>
<ul>
<li>callbackList - Gibt die Liste der eingetragenen Callback URL's wieder.</li>
<li>logFile - Zeigt das Logfile der Bridge an</li>
<br>
</ul>
<br><br>
<a name="NUKIBridgeattribut"></a>
<b>Attribute</b>
<ul>
<li>disable - deaktiviert die Nuki Bridge</li>
<li>webhookFWinstance - zu verwendene Webinstanz für den Callbackaufruf</li>
<li>webhookHttpHostname - IP oder FQDN vom FHEM Server für den Callbackaufruf</li>
<br>
</ul>
</ul>
=end html_DE
=for :application/json;q=META.json 73_NUKIBridge.pm
{
"abstract": "Modul to control the Nuki Smartlock's over the Nuki Bridge",
"x_lang": {
"de": {
"abstract": "Modul to control the Nuki Smartlock's over the Nuki Bridge"
}
},
"keywords": [
"fhem-mod-device",
"fhem-core",
"Smartlock",
"Nuki",
"Control"
],
"release_status": "stable",
"license": "GPL_2",
"version": "v2.0.2",
"x_apiversion": "1.13.0",
"author": [
"Marko Oldenburg <leongaultier@gmail.com>"
],
"x_fhem_maintainer": [
"CoolTux"
],
"x_fhem_maintainer_github": [
"LeonGaultier"
],
"prereqs": {
"runtime": {
"requires": {
"FHEM": 5.00918799,
"perl": 5.024,
"Meta": 0,
"JSON": 0,
"Date::Parse": 0
},
"recommends": {
},
"suggests": {
}
}
}
}
=end :application/json;q=META.json
=cut

302
FHEM/74_NUKIDevice.pm Normal file
View File

@ -0,0 +1,302 @@
###############################################################################
#
# Developed with VSCodium and richterger perl plugin
#
# (c) 2016-2021 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net)
# All rights reserved
#
# This script 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 2 of the License, or
# any later version.
#
# The GNU General Public License can be found at
# http://www.gnu.org/copyleft/gpl.html.
# A copy is found in the textfile GPL.txt and important notices to the license
# from the author is found in LICENSE.txt distributed with these scripts.
#
# This script 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.
#
#
# $Id$
#
###############################################################################
package FHEM::NUKIDevice;
use strict;
use warnings;
use FHEM::Meta;
require FHEM::Devices::Nuki::Device;
use GPUtils qw(GP_Import);
BEGIN {
# Import from main context
GP_Import(qw( readingFnAttributes ));
}
main::LoadModule('NUKIBridge');
sub ::NUKIDevice_Initialize { goto &Initialize }
sub Initialize {
my ($hash) = @_;
$hash->{Match} = '^{.*}$';
$hash->{SetFn} = \&FHEM::Devices::Nuki::Device::Set;
$hash->{DefFn} = \&FHEM::Devices::Nuki::Device::Define;
$hash->{UndefFn} = \&FHEM::Devices::Nuki::Device::Undef;
$hash->{NotifyFn} = \&FHEM::Devices::Nuki::Device::Notify;
$hash->{AttrFn} = \&FHEM::Devices::Nuki::Device::Attr;
$hash->{ParseFn} = \&FHEM::Devices::Nuki::Device::Parse;
$hash->{AttrList} =
'IODev '
. 'model:smartlock,opener,smartdoor,smartlock3 '
. 'disable:1 '
. $readingFnAttributes;
return FHEM::Meta::InitMod( __FILE__, $hash );
}
1;
=pod
=item device
=item summary Modul to control the Nuki Smartlock's
=item summary_DE Modul zur Steuerung des Nuki Smartlocks.
=begin html
<a name="NUKIDevice"></a>
<h3>NUKIDevice</h3>
<ul>
<u><b>NUKIDevice - Controls the Nuki Smartlock</b></u>
<br>
The Nuki module connects FHEM over the Nuki Bridge with a Nuki Smartlock or Nuki Opener. After that, it´s possible to control your Nuki devices<br>
Normally the Nuki devices are automatically created by the bridge module.
<br><br>
<a name="NUKIDevicedefine"></a>
<b>Define</b>
<ul><br>
<code>define &lt;name&gt; NUKIDevice &lt;Nuki-Id&gt; &lt;IODev-Device&gt; &lt;Device-Type&gt;</code>
<br><br>
Device-Type is 0/4 for the Smartlock and 2 for the Opener.
<br><br>
Example:
<ul><br>
<code>define Frontdoor NUKIDevice 1 NBridge1 0</code><br>
</ul>
<br>
This statement creates a NUKIDevice with the name Frontdoor, the NukiId 1 and the IODev device NBridge1.<br>
After the device has been created, the current state of the Smartlock is automatically read from the bridge.
</ul>
<br><br>
<a name="NUKIDevicereadings"></a>
<b>Readings</b>
<br>Smartlock
<ul>
<li>batteryCharging - is the battery charging true/false.</li>
<li>batteryPercent - current battry state in percent.</li>
<li>batteryState - battery state ok/low</li>
<li>deviceType - type name of nuki device smartlock/smartlock3/opener</li>
<li>firmwareVersion - version of device firmware</li>
<li>name - name of the device</li>
<li>nukiid - id of the nuki device</li>
<li>paired - paired information false/true</li>
<li>rssi - value of rssi</li>
<li>state - Status of the Smartlock or error message if any error.</li>
<li>stateName - Status of the Smartlock or error message if any error.</li>
<li>succes - true, false Returns the status of the last closing command. Ok or not Ok.</li>
</ul>
<br>Opener
<ul>
<li>batteryState - battery state ok/low</li>
<li>deviceType - type name of nuki device smartlock/smartlock3/opener</li>
<li>firmwareVersion - version of device firmware</li>
<li>mode - Operation mode (door mode/continuous mode)</li>
<li>name - name of the device</li>
<li>nukiid - id of the nuki device</li>
<li>paired - paired information false/true</li>
<li>ringactionState - state of ring (0/1)</li>
<li>ringactionTimestamp - timestamp of ring</li>
<li>rssi - value of rssi</li>
<li>state - Status of the Smartlock or error message if any error.</li>
<li>stateName - Status of the Smartlock or error message if any error.</li>
<li>succes - true, false Returns the status of the last closing command. Ok or not Ok.</li>
</ul>
<br><br>
<a name="NUKIDeviceset"></a>
<b>Set</b>
<br>Smartlock
<ul>
<li>statusRequest - retrieves the current state of the smartlock from the bridge.</li>
<li>lock - lock</li>
<li>unlock - unlock</li>
<li>unlatch - unlock / open Door</li>
<li>unpair - Removes the pairing with a given Smart Lock</li>
<li>locknGo - lock when gone</li>
<li>locknGoWithUnlatch - lock after the door has been opened</li>
</ul>
<br>Opener
<ul>
<li>statusRequest - retrieves the current state of the smartlock from the bridge.</li>
<li>activateRto - activate ring to open mode / ringing the bell activates the electric strike actuation </li>
<li>deactivateRto - deactivate ring to open mode</li>
<li>electricStrikeActuation - electric strike actuation</li>
<li>activateContinuousMode - activate Nuki Opener Mode with Ring to Open continuously</li>
<li>deactivateContinuousMode - deactivate Ring to Open continuously</li>
</ul>
<br><br>
<a name="NUKIDeviceattribut"></a>
<b>Attributes</b>
<ul>
<li>disable - disables the Nuki device</li>
<br>
</ul>
</ul>
=end html
=begin html_DE
<a name="NUKIDevice"></a>
<h3>NUKIDevice</h3>
<ul>
<u><b>NUKIDevice - Zur Steuerung von Nuki Ger&auml;te</b></u>
<br>
Das Nuki Modul verbindet FHEM &uuml;ber die Nuki Bridge mit einem Nuki Smartlock oder Opener. Nach der Einrichtung k&ouml;nnen diese Ger&auml;te gesteuert werden.<br>
Die Nuki Ger&auml;te werden automatisch nach dem erstellen der Nuki Bridge in FHEM eingerichtet.
<br><br>
<a name="NUKIDevicedefine"></a>
<b>Define</b>
<ul><br>
<code>define &lt;name&gt; NUKIDevice &lt;Nuki-Id&gt; &lt;IODev-Device&gt; &lt;Device-Type&gt;</code>
<br><br>
Der Device-Type kann 0/4 f&uuml;r ein Smartlock sein oder 2 f&uuml;r den Opener.
<br><br>
Example:
<ul><br>
<code>define Frontdoor NUKIDevice 1 NBridge1 0</code><br>
</ul>
<br>
Diese Anweisung erstellt ein NUKIDevice mit Namen Haust&uuml;r, der NukiId 1 sowie dem IODev Device NBridge1.<br>
Nach dem anlegen des Devices wird automatisch der aktuelle Zustand des Smartlocks aus der Bridge gelesen.
</ul>
<br><br>
<a name="NUKIDevicereadings"></a>
<b>Readings</b>
<br>Smartlock
<ul>
<li>batteryCharging - wird die Batterie geladen true/false.</li>
<li>batteryPercent - aktueller Ladestand der Batterie.</li>
<li>batteryState - Staus der Batterie ok/low</li>
<li>deviceType - der Typenname des Nuki Ger&auml;tes smartlock/smartlock3/opener</li>
<li>firmwareVersion - Version der Ger&auml;te Firmware</li>
<li>name - Name des Nuki Ger&auml;tes</li>
<li>nukiid - die Ger&auml;te Id</li>
<li>paired - paired Informationen false/true</li>
<li>rssi - Wert f&uuml;r die empfangene Signalst&auml;rke</li>
<li>state - Status des Smartlock bzw . Fehlermeldung von Fehler vorhanden.</li>
<li>succes - true, false. Gibt den Status des letzen Befehls zur&uuml;ck.</li>
</ul>
<br>Opener
<ul>
<li>batteryCharging - wird die Batterie geladen true/false.</li>
<li>batteryPercent - aktueller Ladestand der Batterie.</li>
<li>batteryState - Staus der Batterie ok/low</li>
<li>deviceType - der Typenname des Nuki Ger&auml;tes smartlock/smartlock3/opener</li>
<li>firmwareVersion - Version der Ger&auml;te Firmware</li>
<li>name - Name des Nuki Ger&auml;tes</li>
<li>nukiid - die Ger&auml;te Id</li>
<li>paired - paired Informationen false/true</li>
<li>ringactionState - Status der Klingel. Wurde eben geklingelt (0/1)</li>
<li>ringactionTimestamp - Zeitstempel des klingelns</li>
<li>rssi - Wert f &uuml;r die empfangene Signalst &auml;rke</li>
<li>state - Status des Opener bzw . Fehlermeldung von Fehler vorhanden.</li>
<li>succes - true, false. Gibt den Status des letzen Befehls zur&uuml;ck.</li>
</ul>
<br><br>
<a name="NUKIDeviceset"></a>
<b>Set</b>
<br>Smartlock
<ul>
<li>statusRequest - ruft den aktuellen Status des Smartlocks von der Bridge ab.</li>
<li>lock - verschlie&szlig;en</li>
<li>unlock - aufschlie&szlig;en</li>
<li>unlatch - entriegeln/Falle &ouml;ffnen.</li>
<li>unpair - entfernt das pairing mit dem Smart Lock</li>
<li>locknGo - verschlie&szlig;en wenn gegangen</li>
<li>locknGoWithUnlatch - verschlie&szlig;en nach dem die Falle ge&ouml;ffnet wurde.</li>
</ul>
<br>Opener
<ul>
<li>statusRequest - ruft den aktuellen Status des Opener von der Bridge ab.</li>
<li>activateRto - aktiviert den ring to open Modus / ein klingeln aktiviert den T&uuml;r&ouml;ffner</li>
<li>deactivateRto - deaktiviert den ring to open Modus</li>
<li>electricStrikeActuation - aktiviert den T&uuml;r&ouml;ffner</li>
<li>activateContinuousMode - aktiviert dauerhaft &ouml;ffnen der T&uuml;r durch klingeln Modus</li>
<li>deactivateContinuousMode - deaktiviert diesen Modus</li>
</ul>
<br><br>
<a name="NUKIDeviceattribut"></a>
<b>Attributes</b>
<ul>
<li>disable - disables the Nuki device</li>
<br>
</ul>
</ul>
=end html_DE
=for :application/json;q=META.json 74_NUKIDevice.pm
{
"abstract": "Modul to control the Nuki Smartlock's over the Nuki Bridge",
"x_lang": {
"de": {
"abstract": "Modul to control the Nuki Smartlock's over the Nuki Bridge"
}
},
"keywords": [
"fhem-mod-device",
"fhem-core",
"Smartlock",
"Nuki",
"Control"
],
"release_status": "stable",
"license": "GPL_2",
"version": "v2.0.2",
"author": [
"Marko Oldenburg <leongaultier@gmail.com>"
],
"x_fhem_maintainer": [
"CoolTux"
],
"x_fhem_maintainer_github": [
"LeonGaultier"
],
"prereqs": {
"runtime": {
"requires": {
"FHEM": 5.00918799,
"perl": 5.024,
"Meta": 0,
"JSON": 0,
"Date::Parse": 0
},
"recommends": {
},
"suggests": {
}
}
}
}
=end :application/json;q=META.json
=cut

18
README.md Normal file
View File

@ -0,0 +1,18 @@
# FHEM::NUKIBridge
# FHEM::NUKIDevice
## Used branching model
* Master branch: Production version (copy of [fhem/fhem-mirror/blob/master/fhem/FHEM/73_NUKIBridge.pm](https://github.com/fhem/fhem-mirror/blob/master/fhem/FHEM/73_NUKIBridge.pm))
* Master branch: Production version (copy of [fhem/fhem-mirror/blob/master/fhem/FHEM/74_NUKIBDevice.pm](https://github.com/fhem/fhem-mirror/blob/master/fhem/FHEM/74_NUKIDevice.pm
* Devel branch: Latest development version
## Community support
The FHEM Forum is available [here](https://forum.fhem.de/) for general support.
In case you have a specific question about this module, it is recommended to find the right sub-forum.
It can either be found from the module info card using the FHEM Installer (e.g. using command `search <MODULE_NAME>`) or it can be determined from the [MAINTAINER.txt](https://github.com/fhem/fhem-mirror/blob/master/fhem/MAINTAINER.txt) file.
## Bug reports and feature requests
Identified bugs and feature requests are tracked using [Github Issues](https://github.com/fhem/Nuki/issues).
## Pull requests / How to participate into development
You are invited to send pull requests to the devel branch whenever you think you can contribute with some useful improvements to the module. The module maintainer will review you code and decide whether it is going to be part of the module in a future release.

4
controls_NukiSmart.txt Normal file
View File

@ -0,0 +1,4 @@
UPD 2021-12-17_12:18:33 10358 FHEM/73_NUKIBridge.pm
UPD 2021-12-17_12:44:59 11100 FHEM/74_NUKIDevice.pm
UPD 2022-09-26_11:59:12 42767 lib/FHEM/Devices/Nuki/Bridge.pm
UPD 2021-12-17_12:18:33 16338 lib/FHEM/Devices/Nuki/Device.pm

41
hooks/pre-commit Executable file
View File

@ -0,0 +1,41 @@
#!/usr/bin/perl -w
use File::Basename;
use POSIX qw(strftime);
use strict;
my @filenames = ( 'FHEM/73_NUKIBridge.pm',
'FHEM/74_NUKIDevice.pm',
'lib/FHEM/Devices/Nuki/Bridge.pm',
'lib/FHEM/Devices/Nuki/Device.pm'
);
my $controlsfile = 'controls_NukiSmart.txt';
open(FH, ">$controlsfile") || return("Can't open $controlsfile: $!");
for my $filename (@filenames) {
my @statOutput = stat($filename);
if (scalar @statOutput != 13) {
printf 'error: stat has unexpected return value for ' . $filename . "\n";
next;
}
my $mtime = $statOutput[9];
my $date = POSIX::strftime("%Y-%m-%d", localtime($mtime));
my $time = POSIX::strftime("%H:%M:%S", localtime($mtime));
my $filetime = $date."_".$time;
my $filesize = $statOutput[7];
printf FH 'UPD ' . $filetime . ' ' . $filesize . ' ' .$filename . "\n";
}
close(FH);
system("git add $controlsfile");
print 'Create controls File succesfully' . "\n";
exit 0;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,610 @@
###############################################################################
#
# Developed with VSCodium and richterger perl plugin
#
# (c) 2016-2021 Copyright: Marko Oldenburg (fhemdevelopment at cooltux dot net)
# All rights reserved
#
# This script 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 2 of the License, or
# any later version.
#
# The GNU General Public License can be found at
# http://www.gnu.org/copyleft/gpl.html.
# A copy is found in the textfile GPL.txt and important notices to the license
# from the author is found in LICENSE.txt distributed with these scripts.
#
# This script 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.
#
#
# $Id$
#
###############################################################################
package FHEM::Devices::Nuki::Device;
use strict;
use warnings;
use experimental qw( switch );
use FHEM::Meta;
use GPUtils qw(GP_Import);
BEGIN {
# Import from main context
GP_Import(
qw( init_done
defs
modules
)
);
}
# try to use JSON::MaybeXS wrapper
# for chance of better performance + open code
eval {
require JSON::MaybeXS;
import JSON::MaybeXS qw( decode_json encode_json );
1;
} or do {
# try to use JSON wrapper
# for chance of better performance
eval {
# JSON preference order
local $ENV{PERL_JSON_BACKEND} =
'Cpanel::JSON::XS,JSON::XS,JSON::PP,JSON::backportPP'
unless ( defined( $ENV{PERL_JSON_BACKEND} ) );
require JSON;
import JSON qw( decode_json encode_json );
1;
} or do {
# In rare cases, Cpanel::JSON::XS may
# be installed but JSON|JSON::MaybeXS not ...
eval {
require Cpanel::JSON::XS;
import Cpanel::JSON::XS qw(decode_json encode_json);
1;
} or do {
# In rare cases, JSON::XS may
# be installed but JSON not ...
eval {
require JSON::XS;
import JSON::XS qw(decode_json encode_json);
1;
} or do {
# Fallback to built-in JSON which SHOULD
# be available since 5.014 ...
eval {
require JSON::PP;
import JSON::PP qw(decode_json encode_json);
1;
} or do {
# Fallback to JSON::backportPP in really rare cases
require JSON::backportPP;
import JSON::backportPP qw(decode_json encode_json);
1;
};
};
};
};
};
######## Begin Device
my %deviceTypes = (
0 => 'smartlock',
2 => 'opener',
3 => 'smartdoor',
4 => 'smartlock3'
);
my %deviceTypeIds = reverse(%deviceTypes);
my %modes = (
2 => {
0 => 'door mode',
2 => 'door mode'
},
3 => {
0 => '-',
2 => ' continuous mode'
}
);
my %lockStates = (
0 => {
0 => 'uncalibrated',
2 => 'untrained',
4 => 'uncalibrated'
},
1 => {
0 => 'locked',
2 => 'online',
4 => 'locked'
},
2 => {
0 => 'unlocking',
2 => '-',
4 => 'unlocking'
},
3 => {
0 => 'unlocked',
2 => 'rto active',
4 => 'unlocked'
},
4 => {
0 => 'locking',
2 => '-',
4 => 'locking'
},
5 => {
0 => 'unlatched',
2 => 'open',
4 => 'unlatched'
},
6 => {
0 => 'unlocked (lock n go)',
2 => '-',
4 => 'unlocked (lock n go)'
},
7 => {
0 => 'unlatching',
2 => 'opening',
4 => 'unlatching'
},
253 => {
0 => '-',
2 => 'boot run',
4 => '-'
},
254 => {
0 => 'motor blocked',
2 => '-',
4 => 'motor blocked'
},
255 => {
0 => 'undefined',
2 => 'undefined',
4 => 'undefined'
}
);
my %doorsensorStates = (
1 => 'deactivated',
2 => 'door closed',
3 => 'door opened',
4 => 'door state unknown',
5 => 'calibrating'
);
sub Define {
my $hash = shift;
my $def = shift // return;
my $version;
return $@ unless ( FHEM::Meta::SetInternals($hash) );
$version = FHEM::Meta::Get( $hash, 'version' );
our $VERSION = $version;
my ( $name, undef, $nukiId, $deviceType ) = split( m{\s+}xms, $def );
return 'too few parameters: define <name> NUKIDevice <nukiId> <deviceType>'
if ( !defined($nukiId)
|| !defined($name) );
$deviceType =
defined($deviceType)
? $deviceType
: 0;
$hash->{NUKIID} = $nukiId;
$hash->{DEVICETYPEID} = $deviceType;
$hash->{VERSION} = version->parse($VERSION)->normal;
$hash->{STATE} = 'Initialized';
$hash->{NOTIFYDEV} = 'global,autocreate,' . $name;
my $iodev = ::AttrVal( $name, 'IODev', 'none' );
::AssignIoPort( $hash, $iodev ) if ( !$hash->{IODev} );
if ( defined( $hash->{IODev}->{NAME} ) ) {
::Log3( $name, 3,
"NUKIDevice ($name) - I/O device is " . $hash->{IODev}->{NAME} );
}
else {
::Log3( $name, 1, "NUKIDevice ($name) - no I/O device" );
}
$iodev = $hash->{IODev}->{NAME};
$hash->{BRIDGEAPI} = $defs{$iodev}->{BRIDGEAPI}
if ( defined($iodev)
&& $iodev );
my $d = $modules{NUKIDevice}{defptr}{$nukiId};
return
'NUKIDevice device '
. $name
. ' on NUKIBridge '
. $iodev
. ' already defined.'
if ( defined($d)
&& $d->{IODev} == $hash->{IODev}
&& $d->{NAME} ne $name );
::Log3( $name, 3, "NUKIDevice ($name) - defined with NukiId: $nukiId" );
::CommandAttr( undef, $name . ' room NUKI' )
if ( ::AttrVal( $name, 'room', 'none' ) eq 'none' );
::CommandAttr( undef, $name . ' model ' . $deviceTypes{$deviceType} )
if ( ::AttrVal( $name, 'model', 'none' ) eq 'none' );
$modules{NUKIDevice}{defptr}{$nukiId} = $hash;
GetUpdate($hash)
if ( ::ReadingsVal( $name, 'success', 'none' ) eq 'none'
&& $init_done );
return;
}
sub Undef {
my $hash = shift;
my $nukiId = $hash->{NUKIID};
my $name = $hash->{NAME};
::Log3( $name, 3, "NUKIDevice ($name) - undefined with NukiId: $nukiId" );
delete( $modules{NUKIDevice}{defptr}{$nukiId} );
return;
}
sub Attr {
my $cmd = shift;
my $name = shift;
my $attrName = shift;
my $attrVal = shift;
my $hash = $defs{$name};
my $token = $hash->{IODev}->{TOKEN};
if ( $attrName eq 'disable' ) {
if ( $cmd eq 'set' && $attrVal == 1 ) {
::readingsSingleUpdate( $hash, 'state', 'disabled', 1 );
::Log3( $name, 3, "NUKIDevice ($name) - disabled" );
}
elsif ( $cmd eq 'del' ) {
::readingsSingleUpdate( $hash, 'state', 'active', 1 );
::Log3( $name, 3, "NUKIDevice ($name) - enabled" );
}
}
elsif ( $attrName eq 'disabledForIntervals' ) {
if ( $cmd eq 'set' ) {
::Log3( $name, 3,
"NUKIDevice ($name) - enable disabledForIntervals" );
::readingsSingleUpdate( $hash, 'state', 'Unknown', 1 );
}
elsif ( $cmd eq 'del' ) {
::readingsSingleUpdate( $hash, 'state', 'active', 1 );
::Log3( $name, 3,
"NUKIDevice ($name) - delete disabledForIntervals" );
}
}
elsif ( $attrName eq 'model' ) {
if ( $cmd eq 'set' ) {
::Log3( $name, 3, "NUKIDevice ($name) - change model" );
$hash->{DEVICETYPEID} = $deviceTypeIds{$attrVal};
}
}
return;
}
sub Notify {
my $hash = shift;
my $dev = shift // return;
my $name = $hash->{NAME};
return if ( ::IsDisabled($name) );
my $devname = $dev->{NAME};
my $devtype = $dev->{TYPE};
my $events = ::deviceEvents( $dev, 1 );
return if ( !$events );
GetUpdate($hash)
if (
(
grep { /^INITIALIZED$/x } @{$events}
or grep { /^REREADCFG$/x } @{$events}
or grep { /^MODIFIED.$name$/x } @{$events}
or grep { /^DEFINED.$name$/x } @{$events}
)
&& $devname eq 'global'
&& $init_done
);
return;
}
sub Set {
my $hash = shift;
my $name = shift;
my $cmd = shift // return "set $name needs at least one argument !";
my $lockAction;
if ( lc($cmd) eq 'statusrequest' ) {
GetUpdate($hash);
return;
}
elsif ($cmd eq 'lock'
|| lc($cmd) eq 'deactivaterto'
|| $cmd eq 'unlock'
|| lc($cmd) eq 'activaterto'
|| $cmd eq 'unlatch'
|| lc($cmd) eq 'electricstrikeactuation'
|| lc($cmd) eq 'lockngo'
|| lc($cmd) eq 'activatecontinuousmode'
|| lc($cmd) eq 'lockngowithunlatch'
|| lc($cmd) eq 'deactivatecontinuousmode'
|| $cmd eq 'unpair' )
{
$lockAction = $cmd;
}
else {
my $list = '';
$list =
'statusRequest:noArg unlock:noArg lock:noArg unlatch:noArg locknGo:noArg locknGoWithUnlatch:noArg unpair:noArg'
if ( $hash->{DEVICETYPEID} == 0
|| $hash->{DEVICETYPEID} == 4 );
$list =
'statusRequest:noArg activateRto:noArg deactivateRto:noArg electricStrikeActuation:noArg activateContinuousMode:noArg deactivateContinuousMode:noArg unpair:noArg'
if ( $hash->{DEVICETYPEID} == 2 );
return ( 'Unknown argument ' . $cmd . ', choose one of ' . $list );
}
$hash->{helper}{lockAction} = $lockAction;
::IOWrite( $hash, 'lockAction',
'{"param":"'
. $lockAction
. '","nukiId":'
. $hash->{NUKIID}
. ',"deviceType":'
. $hash->{DEVICETYPEID}
. '}' );
return;
}
sub GetUpdate {
my $hash = shift;
my $name = $hash->{NAME};
if ( !::IsDisabled($name) ) {
::IOWrite( $hash, 'lockState',
'{"nukiId":'
. $hash->{NUKIID}
. ',"deviceType":'
. $hash->{DEVICETYPEID}
. '}' );
::Log3( $name, 2, "NUKIDevice ($name) - GetUpdate Call IOWrite" );
}
return;
}
sub Parse {
my $hash = shift;
my $json = shift // return;
my $name = $hash->{NAME};
::Log3( $name, 5, "NUKIDevice ($name) - Parse with result: $json" );
#########################################
####### Errorhandling #############
if ( $json !~ m{\A[\[{].*[}\]]\z}xms ) {
::Log3( $name, 3, "NUKIDevice ($name) - invalid json detected: $json" );
return "NUKIDevice ($name) - invalid json detected: $json";
}
#########################################
#### verarbeiten des JSON Strings #######
my $decode_json = eval { decode_json($json) };
if ($@) {
::Log3( $name, 3, "NUKIDevice ($name) - JSON error while request: $@" );
return;
}
if ( ref($decode_json) ne 'HASH' ) {
::Log3( $name, 2,
"NUKIDevice ($name) - got wrong status message for $name: $decode_json"
);
return;
}
my $nukiId = $decode_json->{nukiId};
if ( my $dhash = $modules{NUKIDevice}{defptr}{$nukiId} ) {
my $dname = $dhash->{NAME};
WriteReadings( $dhash, $decode_json );
::Log3( $dname, 4,
"NUKIDevice ($dname) - find logical device: $dhash->{NAME}" );
return $dhash->{NAME};
}
else {
::Log3( $name, 4,
"NUKIDevice ($name) - autocreate new device "
. ::makeDeviceName( $decode_json->{name} )
. " with nukiId $decode_json->{nukiId}, model $decode_json->{deviceType}"
);
return
'UNDEFINED '
. ::makeDeviceName( $decode_json->{name} )
. " NUKIDevice $decode_json->{nukiId} $decode_json->{deviceType}";
}
::Log3( $name, 5, "NUKIDevice ($name) - parse status message for $name" );
return WriteReadings( $hash, $decode_json );
}
sub SmartlockState {
############################
#### Status des Smartlock
my $hash = shift;
my $decode_json = shift;
if ( defined( $hash->{helper}{lockAction} ) ) {
my $state;
if (
defined( $decode_json->{success} )
&& ( $decode_json->{success} eq 'true'
|| $decode_json->{success} == 1 )
)
{
$state = $hash->{helper}{lockAction};
::IOWrite( $hash, 'lockState',
'{"nukiId":'
. $hash->{NUKIID}
. ',"deviceType":'
. $hash->{DEVICETYPEID}
. '}' )
if (
::ReadingsVal( $hash->{IODev}->{NAME},
'bridgeType', 'Software' ) eq 'Software'
);
}
elsif (
defined( $decode_json->{success} )
&& ( $decode_json->{success} eq 'false'
|| $decode_json->{success} == 0 )
)
{
$state = $deviceTypes{ $hash->{DEVICETYPEID} } . ' response error';
::IOWrite( $hash, 'lockState',
'{"nukiId":'
. $hash->{NUKIID}
. ',"deviceType":'
. $hash->{DEVICETYPEID}
. '}' );
}
$decode_json->{'state'} = $state;
delete $hash->{helper}{lockAction};
}
return $decode_json;
}
sub WriteReadings {
my $hash = shift;
my $decode_json = shift;
my $name = $hash->{NAME};
$decode_json = SmartlockState( $hash, $decode_json );
::readingsBeginUpdate($hash);
my $t;
my $v;
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 )
if ( $t ne 'state'
&& $t ne 'mode'
&& $t ne 'deviceType'
&& $t ne 'paired'
&& $t ne 'batteryCritical'
&& $t ne 'batteryChargeState'
&& $t ne 'batteryCharging'
&& $t ne 'timestamp'
&& $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,
$modes{$v}{ $hash->{DEVICETYPEID} } );
}
when ('deviceType') {
::readingsBulkUpdate( $hash, $t, $deviceTypes{$v} );
}
when ('doorsensorState') {
::readingsBulkUpdate( $hash, $t, $doorsensorStates{$v} );
}
when ('paired') {
::readingsBulkUpdate( $hash, $t,
( $v == 1 ? 'true' : 'false' ) );
}
when ('batteryCharging') {
::readingsBulkUpdate( $hash, $t,
( $v == 1 ? 'true' : 'false' ) );
}
when ('batteryCritical') {
::readingsBulkUpdate( $hash, 'batteryState',
( $v == 1 ? 'low' : 'ok' ) );
}
when ('batteryChargeState') {
::readingsBulkUpdate( $hash, 'batteryPercent', $v )
}
}
}
::readingsEndUpdate( $hash, 1 );
::Log3( $name, 5,
"NUKIDevice ($name) - lockAction readings set for $name" );
return;
}
1;