2016-09-27 11:37:19 +00:00
###############################################################################
#
# Developed with Kate
#
2020-01-08 12:26:22 +00:00
# (c) 2016-2020 Copyright: Marko Oldenburg (leongaultier at gmail dot com)
2016-09-27 11:37:19 +00:00
# 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$
#
###############################################################################
2016-10-30 12:45:03 +00:00
#################################
######### Wichtige Hinweise und Links #################
## Beispiel für Logausgabe
# https://forum.fhem.de/index.php/topic,55756.msg508412.html#msg508412
##
#
################################
2016-09-27 11:37:19 +00:00
package main ;
use strict ;
use warnings ;
use JSON ;
2016-11-03 16:58:01 +00:00
2016-09-27 11:37:19 +00:00
use HttpUtils ;
2020-01-08 15:30:42 +00:00
my $ version = "0.7.9" ;
2019-12-21 20:52:18 +00:00
my $ bridgeapi = "1.9" ;
2016-09-27 11:37:19 +00:00
2019-12-21 20:52:18 +00:00
my % lockActionsSmartLock = (
'unlock' = > 1 ,
'lock' = > 2 ,
'unlatch' = > 3 ,
'locknGo' = > 4 ,
'locknGoWithUnlatch' = > 5
) ;
my % lockActionsOpener = (
'activateRto' = > 1 ,
'deactivateRto' = > 2 ,
'electricStrikeActuation' = > 3 ,
'activateContinuousMode' = > 4 ,
'deactivateContinuousMode' = > 5
2016-09-27 11:37:19 +00:00
) ;
2017-01-17 05:18:25 +00:00
# Declare functions
sub NUKIBridge_Initialize ($) ;
sub NUKIBridge_Define ($$) ;
sub NUKIBridge_Undef ($$) ;
sub NUKIBridge_Read ($@) ;
sub NUKIBridge_Attr (@) ;
2019-12-17 20:49:21 +00:00
sub NUKIBridge_addExtension ($$$) ;
sub NUKIBridge_removeExtension ($) ;
2017-01-17 05:18:25 +00:00
sub NUKIBridge_Set ($@) ;
sub NUKIBridge_Get ($@) ;
sub NUKIBridge_GetCheckBridgeAlive ($) ;
sub NUKIBridge_firstRun ($) ;
2020-01-08 15:30:42 +00:00
sub NUKIBridge_Write ($@) ;
2017-01-17 05:18:25 +00:00
sub NUKIBridge_Distribution ($$$) ;
sub NUKIBridge_ResponseProcessing ($$$) ;
2019-12-17 20:49:21 +00:00
sub NUKIBridge_CGI () ;
2017-01-17 05:18:25 +00:00
sub NUKIBridge_Autocreate ( $ $ ; $ ) ;
sub NUKIBridge_InfoProcessing ($$) ;
sub NUKIBridge_getLogfile ($) ;
sub NUKIBridge_getCallbackList ($) ;
2020-01-08 22:24:01 +00:00
sub NUKIBridge_CallBlocking ($@) ;
2017-01-17 05:18:25 +00:00
2017-11-21 17:15:15 +00:00
2016-09-27 11:37:19 +00:00
sub NUKIBridge_Initialize ($) {
my ( $ hash ) = @ _ ;
2020-01-08 12:26:22 +00:00
2016-09-27 11:37:19 +00:00
# Provider
2020-01-08 15:30:42 +00:00
$ hash - > { WriteFn } = "NUKIBridge_Write" ;
2020-01-08 12:26:22 +00:00
$ hash - > { Clients } = ':NUKIDevice:' ;
2020-01-08 15:30:42 +00:00
$ hash - > { MatchList } = { '1:NUKIDevice' = > '^{.*}$' } ;
2016-09-27 11:37:19 +00:00
2019-12-17 20:49:21 +00:00
my $ webhookFWinstance = join ( "," , devspec2array ( 'TYPE=FHEMWEB:FILTER=TEMPORARY!=1' ) ) ;
2016-11-03 16:58:01 +00:00
2016-09-27 11:37:19 +00:00
# Consumer
$ hash - > { SetFn } = "NUKIBridge_Set" ;
2016-10-30 21:24:52 +00:00
$ hash - > { GetFn } = "NUKIBridge_Get" ;
2016-12-17 19:47:58 +00:00
$ hash - > { DefFn } = "NUKIBridge_Define" ;
$ hash - > { UndefFn } = "NUKIBridge_Undef" ;
$ hash - > { AttrFn } = "NUKIBridge_Attr" ;
$ hash - > { AttrList } = "disable:1 " .
2019-12-17 20:49:21 +00:00
"webhookFWinstance:$webhookFWinstance " .
"webhookHttpHostname " .
2016-09-27 11:37:19 +00:00
$ readingFnAttributes ;
foreach my $ d ( sort keys % { $ modules { NUKIBridge } { defptr } } ) {
2016-12-17 19:47:58 +00:00
my $ hash = $ modules { NUKIBridge } { defptr } { $ d } ;
$ hash - > { VERSION } = $ version ;
2016-09-27 11:37:19 +00:00
}
}
sub NUKIBridge_Define ($$) {
my ( $ hash , $ def ) = @ _ ;
my @ a = split ( "[ \t][ \t]*" , $ def ) ;
return "too few parameters: define <name> NUKIBridge <HOST> <TOKEN>" if ( @ a != 4 ) ;
2016-12-17 19:47:58 +00:00
my $ name = $ a [ 0 ] ;
my $ host = $ a [ 2 ] ;
2016-09-27 11:37:19 +00:00
my $ token = $ a [ 3 ] ;
2016-12-17 19:47:58 +00:00
my $ port = 8080 ;
2016-09-27 11:37:19 +00:00
2016-12-17 19:47:58 +00:00
$ hash - > { HOST } = $ host ;
$ hash - > { PORT } = $ port ;
$ hash - > { TOKEN } = $ token ;
$ hash - > { VERSION } = $ version ;
2017-01-19 20:07:38 +00:00
$ hash - > { BRIDGEAPI } = $ bridgeapi ;
2016-12-17 19:47:58 +00:00
$ hash - > { helper } { aliveCount } = 0 ;
2019-12-17 20:49:21 +00:00
my $ infix = "NUKIBridge" ;
2016-09-27 11:37:19 +00:00
Log3 $ name , 3 , "NUKIBridge ($name) - defined with host $host on port $port, Token $token" ;
$ attr { $ name } { room } = "NUKI" if ( ! defined ( $ attr { $ name } { room } ) ) ;
2019-12-17 20:49:21 +00:00
if ( NUKIBridge_addExtension ( $ name , "NUKIBridge_CGI" , $ infix . "-" . $ host ) ) {
$ hash - > { fhem } { infix } = $ infix ;
}
$ hash - > { WEBHOOK_REGISTER } = "unregistered" ;
2017-11-21 17:15:15 +00:00
readingsSingleUpdate ( $ hash , 'state' , 'Initialized' , 1 ) ;
2016-09-27 11:37:19 +00:00
RemoveInternalTimer ( $ hash ) ;
2016-09-27 22:21:44 +00:00
2016-11-13 09:44:02 +00:00
if ( $ init_done ) {
NUKIBridge_firstRun ( $ hash ) if ( ( $ hash - > { HOST } ) and ( $ hash - > { TOKEN } ) ) ;
} else {
2017-01-09 20:30:12 +00:00
InternalTimer ( gettimeofday ( ) + 15 , 'NUKIBridge_firstRun' , $ hash , 0 ) if ( ( $ hash - > { HOST } ) and ( $ hash - > { TOKEN } ) ) ;
2016-11-13 09:44:02 +00:00
}
2016-09-27 11:37:19 +00:00
2016-09-27 22:21:44 +00:00
$ modules { NUKIBridge } { defptr } { $ hash - > { HOST } } = $ hash ;
2016-09-27 11:37:19 +00:00
return undef ;
}
sub NUKIBridge_Undef ($$) {
my ( $ hash , $ arg ) = @ _ ;
my $ host = $ hash - > { HOST } ;
my $ name = $ hash - > { NAME } ;
2019-12-17 20:49:21 +00:00
if ( defined ( $ hash - > { fhem } { infix } ) ) {
NUKIBridge_removeExtension ( $ hash - > { fhem } { infix } ) ;
}
2016-09-27 11:37:19 +00:00
RemoveInternalTimer ( $ hash ) ;
2016-09-27 22:21:44 +00:00
delete $ modules { NUKIBridge } { defptr } { $ hash - > { HOST } } ;
2016-09-27 11:37:19 +00:00
return undef ;
}
sub NUKIBridge_Attr (@) {
my ( $ cmd , $ name , $ attrName , $ attrVal ) = @ _ ;
my $ hash = $ defs { $ name } ;
my $ orig = $ attrVal ;
2016-12-12 13:23:51 +00:00
2016-09-27 11:37:19 +00:00
if ( $ attrName eq "disable" ) {
2016-12-12 13:23:51 +00:00
if ( $ cmd eq "set" and $ attrVal eq "1" ) {
2016-12-17 19:47:58 +00:00
readingsSingleUpdate ( $ hash , "state" , "disabled" , 1 ) ;
2016-12-12 13:23:51 +00:00
Log3 $ name , 3 , "NUKIBridge ($name) - disabled" ;
2016-12-17 19:47:58 +00:00
}
elsif ( $ cmd eq "del" ) {
2016-12-12 13:23:51 +00:00
readingsSingleUpdate ( $ hash , "state" , "active" , 1 ) ;
Log3 $ name , 3 , "NUKIBridge ($name) - enabled" ;
2016-09-27 11:37:19 +00:00
}
}
2016-12-12 13:23:51 +00:00
if ( $ attrName eq "disabledForIntervals" ) {
2016-12-17 19:47:58 +00:00
if ( $ cmd eq "set" ) {
2016-12-12 13:23:51 +00:00
Log3 $ name , 3 , "NUKIBridge ($name) - enable disabledForIntervals" ;
readingsSingleUpdate ( $ hash , "state" , "Unknown" , 1 ) ;
2016-12-17 19:47:58 +00:00
}
elsif ( $ cmd eq "del" ) {
2016-12-12 13:23:51 +00:00
readingsSingleUpdate ( $ hash , "state" , "active" , 1 ) ;
Log3 $ name , 3 , "NUKIBridge ($name) - delete disabledForIntervals" ;
2016-11-03 16:58:01 +00:00
}
}
2019-12-17 20:49:21 +00:00
######################
#### webhook #########
return "Invalid value for attribute $attrName: can only by FQDN or IPv4 or IPv6 address" if ( $ attrVal && $ attrName eq "webhookHttpHostname" && $ attrVal !~ /^([A-Za-z_.0-9]+\.[A-Za-z_.0-9]+)|[0-9:]+$/ ) ;
return "Invalid value for attribute $attrName: FHEMWEB instance $attrVal not existing" if ( $ attrVal && $ attrName eq "webhookFWinstance" && ( ! defined ( $ defs { $ attrVal } ) || $ defs { $ attrVal } { TYPE } ne "FHEMWEB" ) ) ;
return "Invalid value for attribute $attrName: needs to be an integer value" if ( $ attrVal && $ attrName eq "webhookPort" && $ attrVal !~ /^\d+$/ ) ;
if ( $ attrName =~ /^webhook.*/ ) {
my $ webhookHttpHostname = ( $ attrName eq "webhookHttpHostname" ? $ attrVal : AttrVal ( $ name , "webhookHttpHostname" , "" ) ) ;
my $ webhookFWinstance = ( $ attrName eq "webhookFWinstance" ? $ attrVal : AttrVal ( $ name , "webhookFWinstance" , "" ) ) ;
$ hash - > { WEBHOOK_URI } = "/" . AttrVal ( $ webhookFWinstance , "webname" , "fhem" ) . "/NUKIBridge" . "-" . $ hash - > { HOST } ;
$ hash - > { WEBHOOK_PORT } = ( $ attrName eq "webhookPort" ? $ attrVal : AttrVal ( $ name , "webhookPort" , InternalVal ( $ webhookFWinstance , "PORT" , "" ) ) ) ;
$ hash - > { WEBHOOK_URL } = "" ;
$ hash - > { WEBHOOK_COUNTER } = "0" ;
if ( $ webhookHttpHostname ne "" && $ hash - > { WEBHOOK_PORT } ne "" ) {
$ hash - > { WEBHOOK_URL } = "http://" . $ webhookHttpHostname . ":" . $ hash - > { WEBHOOK_PORT } . $ hash - > { WEBHOOK_URI } ;
my $ url = "http://$webhookHttpHostname" . ":" . $ hash - > { WEBHOOK_PORT } . $ hash - > { WEBHOOK_URI } ;
Log3 $ name , 3 , "NUKIBridge ($name) - URL ist: $url" ;
2020-01-08 15:30:42 +00:00
NUKIBridge_Write ( $ hash , "callback/add" , $ url , undef , undef ) if ( $ init_done ) ;
2019-12-17 20:49:21 +00:00
$ hash - > { WEBHOOK_REGISTER } = "sent" ;
} else {
$ hash - > { WEBHOOK_REGISTER } = "incomplete_attributes" ;
}
}
2016-12-12 13:23:51 +00:00
2016-09-27 11:37:19 +00:00
return undef ;
}
2019-12-17 20:49:21 +00:00
sub NUKIBridge_addExtension ($$$) {
my ( $ name , $ func , $ link ) = @ _ ;
my $ url = "/$link" ;
Log3 $ name , 2 , "NUKIBridge ($name) - Registering NUKIBridge for webhook URI $url ..." ;
$ data { FWEXT } { $ url } { deviceName } = $ name ;
$ data { FWEXT } { $ url } { FUNC } = $ func ;
$ data { FWEXT } { $ url } { LINK } = $ link ;
return 1 ;
}
sub NUKIBridge_removeExtension ($) {
my ( $ link ) = @ _ ;
my $ url = "/$link" ;
my $ name = $ data { FWEXT } { $ url } { deviceName } ;
Log3 $ name , 2 , "NUKIBridge ($name) - Unregistering NUKIBridge for webhook URL $url..." ;
delete $ data { FWEXT } { $ url } ;
}
2016-09-27 11:37:19 +00:00
sub NUKIBridge_Set ($@) {
my ( $ hash , $ name , $ cmd , @ args ) = @ _ ;
my ( $ arg , @ params ) = @ args ;
2016-09-28 11:57:32 +00:00
if ( $ cmd eq 'autocreate' ) {
return "usage: autocreate" if ( @ args != 0 ) ;
2016-09-27 11:37:19 +00:00
2020-01-08 15:30:42 +00:00
NUKIBridge_Write ( $ hash , "list" , undef , undef , undef ) if ( ! IsDisabled ( $ name ) ) ;
2016-09-28 11:57:32 +00:00
2016-09-27 11:37:19 +00:00
return undef ;
2016-11-16 10:33:03 +00:00
} elsif ( $ cmd eq 'info' ) {
2016-11-03 16:58:01 +00:00
return "usage: statusRequest" if ( @ args != 0 ) ;
2016-09-28 11:57:32 +00:00
2020-01-08 15:30:42 +00:00
NUKIBridge_Write ( $ hash , "info" , undef , undef , undef ) if ( ! IsDisabled ( $ name ) ) ;
2016-09-28 11:57:32 +00:00
return undef ;
2016-09-27 11:37:19 +00:00
2016-11-03 16:58:01 +00:00
} elsif ( $ cmd eq 'fwUpdate' ) {
return "usage: fwUpdate" if ( @ args != 0 ) ;
2016-12-17 19:47:58 +00:00
NUKIBridge_CallBlocking ( $ hash , "fwupdate" , undef ) if ( ! IsDisabled ( $ name ) ) ;
2016-11-03 16:58:01 +00:00
return undef ;
} elsif ( $ cmd eq 'reboot' ) {
return "usage: reboot" if ( @ args != 0 ) ;
2016-12-17 19:47:58 +00:00
NUKIBridge_CallBlocking ( $ hash , "reboot" , undef ) if ( ! IsDisabled ( $ name ) ) ;
2016-11-03 16:58:01 +00:00
return undef ;
} elsif ( $ cmd eq 'clearLog' ) {
return "usage: clearLog" if ( @ args != 0 ) ;
2016-12-17 19:47:58 +00:00
NUKIBridge_CallBlocking ( $ hash , "clearlog" , undef ) if ( ! IsDisabled ( $ name ) ) ;
2016-12-12 13:23:51 +00:00
2017-01-19 20:07:38 +00:00
} elsif ( $ cmd eq 'factoryReset' ) {
return "usage: clearLog" if ( @ args != 0 ) ;
NUKIBridge_CallBlocking ( $ hash , "factoryReset" , undef ) if ( ! IsDisabled ( $ name ) ) ;
2016-12-12 13:23:51 +00:00
} elsif ( $ cmd eq 'callbackRemove' ) {
return "usage: callbackRemove" if ( @ args != 1 ) ;
my $ id = "id=" . join ( " " , @ args ) ;
2016-12-17 19:47:58 +00:00
my $ resp = NUKIBridge_CallBlocking ( $ hash , "callback/remove" , $ id ) if ( ! IsDisabled ( $ name ) ) ;
2019-12-17 20:49:21 +00:00
if ( ( $ resp - > { success } eq "true" or $ resp - > { success } == 1 ) and ! IsDisabled ( $ name ) ) {
2016-12-12 13:23:51 +00:00
return "Success Callback $id removed" ;
} else {
return "remove Callback failed" ;
}
2016-09-27 11:37:19 +00:00
} else {
2017-01-04 12:44:06 +00:00
my $ list = "" ;
2017-11-21 17:15:15 +00:00
$ list . = "info:noArg autocreate:noArg callbackRemove:0,1,2 " ;
2017-01-19 20:07:38 +00:00
$ list . = "clearLog:noArg fwUpdate:noArg reboot:noArg factoryReset:noArg" if ( ReadingsVal ( $ name , 'bridgeType' , 'Software' ) eq 'Hardware' ) ;
2016-09-27 11:37:19 +00:00
return "Unknown argument $cmd, choose one of $list" ;
}
}
2016-10-30 21:24:52 +00:00
sub NUKIBridge_Get ($@) {
my ( $ hash , $ name , $ cmd , @ args ) = @ _ ;
my ( $ arg , @ params ) = @ args ;
if ( $ cmd eq 'logFile' ) {
return "usage: logFile" if ( @ args != 0 ) ;
2016-12-17 19:47:58 +00:00
NUKIBridge_getLogfile ( $ hash ) if ( ! IsDisabled ( $ name ) ) ;
2016-10-30 21:24:52 +00:00
2016-12-12 13:23:51 +00:00
} elsif ( $ cmd eq 'callbackList' ) {
return "usage: callbackList" if ( @ args != 0 ) ;
2016-12-17 19:47:58 +00:00
NUKIBridge_getCallbackList ( $ hash ) if ( ! IsDisabled ( $ name ) ) ;
2016-12-12 13:23:51 +00:00
2016-10-30 21:24:52 +00:00
} else {
2017-01-07 08:31:09 +00:00
my $ list = "" ;
2017-01-10 20:02:39 +00:00
$ list . = "callbackList:noArg " ;
$ list . = "logFile:noArg" if ( ReadingsVal ( $ name , 'bridgeType' , 'Software' ) eq 'Hardware' ) ;
2016-10-30 21:24:52 +00:00
return "Unknown argument $cmd, choose one of $list" ;
}
}
2016-12-10 17:47:56 +00:00
sub NUKIBridge_GetCheckBridgeAlive ($) {
2016-09-27 11:37:19 +00:00
my ( $ hash ) = @ _ ;
my $ name = $ hash - > { NAME } ;
2017-01-10 20:02:39 +00:00
RemoveInternalTimer ( $ hash ) ;
2016-12-17 09:06:10 +00:00
Log3 $ name , 4 , "NUKIBridge ($name) - NUKIBridge_GetCheckBridgeAlive" ;
2016-09-28 11:57:32 +00:00
2016-12-10 17:47:56 +00:00
if ( ! IsDisabled ( $ name ) ) {
2020-01-08 15:30:42 +00:00
NUKIBridge_Write ( $ hash , 'info' , undef , undef , undef ) ;
2016-12-10 17:47:56 +00:00
2020-01-08 15:30:42 +00:00
Log3 $ name , 4 , "NUKIBridge ($name) - run NUKIBridge_Write" ;
2016-12-10 17:47:56 +00:00
}
2017-01-17 05:18:25 +00:00
2020-01-08 22:24:01 +00:00
InternalTimer ( gettimeofday ( ) + 15 + int ( rand ( 45 ) ) , 'NUKIBridge_GetCheckBridgeAlive' , $ hash , 1 ) ;
2017-01-17 05:18:25 +00:00
Log3 $ name , 4 , "NUKIBridge ($name) - Call InternalTimer for NUKIBridge_GetCheckBridgeAlive" ;
2016-12-10 17:47:56 +00:00
}
sub NUKIBridge_firstRun ($) {
my ( $ hash ) = @ _ ;
my $ name = $ hash - > { NAME } ;
2017-01-10 20:02:39 +00:00
RemoveInternalTimer ( $ hash ) ;
2020-01-08 15:30:42 +00:00
NUKIBridge_Write ( $ hash , 'list' , undef , undef , undef ) if ( ! IsDisabled ( $ name ) ) ;
2017-01-09 20:30:12 +00:00
InternalTimer ( gettimeofday ( ) + 15 , 'NUKIBridge_GetCheckBridgeAlive' , $ hash , 1 ) ;
2016-09-28 11:57:32 +00:00
2016-11-16 10:33:03 +00:00
return undef ;
2016-09-27 11:37:19 +00:00
}
2020-01-08 15:30:42 +00:00
sub NUKIBridge_Write ($@) {
my ( $ hash , $ path , $ lockAction , $ nukiId , $ deviceType ) = @ _ ;
2016-09-27 11:37:19 +00:00
my $ name = $ hash - > { NAME } ;
my $ host = $ hash - > { HOST } ;
my $ port = $ hash - > { PORT } ;
my $ token = $ hash - > { TOKEN } ;
2017-11-21 17:15:15 +00:00
2016-09-28 11:57:32 +00:00
2016-09-27 11:37:19 +00:00
my $ uri = "http://" . $ hash - > { HOST } . ":" . $ port ;
$ uri . = "/" . $ path if ( defined $ path ) ;
$ uri . = "?token=" . $ token if ( defined ( $ token ) ) ;
2020-01-08 15:30:42 +00:00
$ uri . = "&action=" . $ lockActionsSmartLock { $ lockAction } if ( defined ( $ lockAction ) and $ path ne "callback/add" and $ deviceType == 0 ) ;
$ uri . = "&action=" . $ lockActionsOpener { $ lockAction } if ( defined ( $ lockAction ) and $ path ne "callback/add" and $ deviceType == 2 ) ;
2016-12-12 13:23:51 +00:00
$ uri . = "&url=" . $ lockAction if ( defined ( $ lockAction ) and $ path eq "callback/add" ) ;
2016-09-28 11:57:32 +00:00
$ uri . = "&nukiId=" . $ nukiId if ( defined ( $ nukiId ) ) ;
2019-12-21 20:52:18 +00:00
$ uri . = "&deviceType=" . $ deviceType if ( defined ( $ deviceType ) ) ;
2016-09-27 11:37:19 +00:00
2017-11-12 10:09:20 +00:00
2016-09-27 11:37:19 +00:00
HttpUtils_NonblockingGet (
2016-12-17 19:47:58 +00:00
{
2020-01-08 15:30:42 +00:00
url = > $ uri ,
2020-01-08 22:24:01 +00:00
timeout = > 60 ,
2020-01-08 15:30:42 +00:00
hash = > $ hash ,
nukiId = > $ nukiId ,
endpoint = > $ path ,
header = > "Accept: application/json" ,
method = > "GET" ,
callback = > \ & NUKIBridge_Distribution ,
2016-12-17 19:47:58 +00:00
}
2016-09-27 11:37:19 +00:00
) ;
2016-10-08 11:37:39 +00:00
Log3 $ name , 4 , "NUKIBridge ($name) - Send HTTP POST with URL $uri" ;
2016-09-27 11:37:19 +00:00
}
2016-11-01 12:39:13 +00:00
sub NUKIBridge_Distribution ($$$) {
2016-09-27 11:37:19 +00:00
my ( $ param , $ err , $ json ) = @ _ ;
2016-11-16 10:33:03 +00:00
my $ hash = $ param - > { hash } ;
my $ doTrigger = $ param - > { doTrigger } ;
my $ name = $ hash - > { NAME } ;
my $ host = $ hash - > { HOST } ;
2016-11-01 12:39:13 +00:00
2020-01-08 15:30:42 +00:00
my $ dhash = $ hash ;
$ dhash = $ modules { NUKIDevice } { defptr } { $ param - > { 'nukiId' } }
unless ( not defined ( $ param - > { 'nukiId' } ) ) ;
my $ dname = $ dhash - > { NAME } ;
2016-11-01 12:39:13 +00:00
2017-01-07 08:31:09 +00:00
Log3 $ name , 5 , "NUKIBridge ($name) - Response JSON: $json" ;
Log3 $ name , 5 , "NUKIBridge ($name) - Response ERROR: $err" ;
2017-05-15 10:33:41 +00:00
Log3 $ name , 5 , "NUKIBridge ($name) - Response CODE: $param->{code}" if ( defined ( $ param - > { code } ) and ( $ param - > { code } ) ) ;
2017-11-21 17:15:15 +00:00
2016-09-28 11:57:32 +00:00
readingsBeginUpdate ( $ hash ) ;
2016-09-27 11:37:19 +00:00
if ( defined ( $ err ) ) {
2016-12-17 19:47:58 +00:00
if ( $ err ne "" ) {
2017-01-07 08:31:09 +00:00
if ( $ param - > { endpoint } eq "info" ) {
2016-12-17 19:47:58 +00:00
readingsBulkUpdate ( $ hash , "state" , "not connected" ) if ( $ hash - > { helper } { aliveCount } > 1 ) ;
2017-01-07 08:31:09 +00:00
Log3 $ name , 5 , "NUKIBridge ($name) - Bridge ist offline" ;
2016-12-17 19:47:58 +00:00
$ hash - > { helper } { aliveCount } = $ hash - > { helper } { aliveCount } + 1 ;
2016-12-10 17:47:56 +00:00
}
readingsBulkUpdate ( $ hash , "lastError" , $ err ) if ( ReadingsVal ( $ name , "state" , "not connected" ) eq "not connected" ) ;
2016-12-11 06:20:23 +00:00
Log3 $ name , 4 , "NUKIBridge ($name) - error while requesting: $err" ;
2016-09-28 11:57:32 +00:00
readingsEndUpdate ( $ hash , 1 ) ;
return $ err ;
2016-12-17 19:47:58 +00:00
}
2016-09-27 11:37:19 +00:00
}
2017-11-21 17:15:15 +00:00
if ( $ json eq "" and exists ( $ param - > { code } ) and $ param - > { code } ne 200 ) {
2017-01-17 05:18:25 +00:00
2017-11-21 17:15:15 +00:00
if ( $ param - > { code } eq 503 ) {
2020-01-08 15:30:42 +00:00
# NUKIDevice_Parse($dhash,$param->{code}) if( $hash != $dhash );
2017-11-21 17:15:15 +00:00
Log3 $ name , 4 , "NUKIBridge ($name) - smartlock is offline" ;
2017-01-17 05:18:25 +00:00
readingsEndUpdate ( $ hash , 1 ) ;
2017-11-21 17:15:15 +00:00
return "received http code " . $ param - > { code } . ": smartlock is offline" ;
2017-01-17 05:18:25 +00:00
}
2016-12-10 17:47:56 +00:00
2016-09-28 11:57:32 +00:00
readingsBulkUpdate ( $ hash , "lastError" , "Internal error, " . $ param - > { code } ) ;
2016-12-17 19:47:58 +00:00
Log3 $ name , 4 , "NUKIBridge ($name) - received http code " . $ param - > { code } . " without any data after requesting" ;
2016-09-27 11:37:19 +00:00
2016-12-17 19:47:58 +00:00
readingsEndUpdate ( $ hash , 1 ) ;
return "received http code " . $ param - > { code } . " without any data after requesting" ;
2016-09-27 11:37:19 +00:00
}
if ( ( $ json =~ /Error/i ) and exists ( $ param - > { code } ) ) {
2016-09-28 11:57:32 +00:00
readingsBulkUpdate ( $ hash , "lastError" , "invalid API token" ) if ( $ param - > { code } eq 401 ) ;
2020-01-08 15:30:42 +00:00
readingsBulkUpdate ( $ hash , "lastError" , "action is undefined" ) if ( $ param - > { code } eq 400 and $ hash == $ dhash ) ;
2016-09-28 20:01:55 +00:00
###### Fehler bei Antwort auf Anfrage eines logischen Devices ######
2020-01-08 15:30:42 +00:00
# NUKIDevice_Parse($dhash,$param->{code}) if( $param->{code} eq 404 );
# NUKIDevice_Parse($dhash,$param->{code}) if( $param->{code} eq 400 and $hash != $dhash );
2017-01-17 05:18:25 +00:00
2016-09-28 20:01:55 +00:00
2016-09-28 11:57:32 +00:00
2016-12-17 19:47:58 +00:00
Log3 $ name , 4 , "NUKIBridge ($name) - invalid API token" if ( $ param - > { code } eq 401 ) ;
Log3 $ name , 4 , "NUKIBridge ($name) - nukiId is not known" if ( $ param - > { code } eq 404 ) ;
2020-01-08 15:30:42 +00:00
Log3 $ name , 4 , "NUKIBridge ($name) - action is undefined" if ( $ param - > { code } eq 400 and $ hash == $ dhash ) ;
2016-12-17 19:47:58 +00:00
2016-09-28 20:01:55 +00:00
2016-09-28 11:57:32 +00:00
readingsEndUpdate ( $ hash , 1 ) ;
2016-12-17 19:47:58 +00:00
return $ param - > { code } ;
2016-09-28 11:57:32 +00:00
}
2017-11-21 17:15:15 +00:00
2020-01-08 15:30:42 +00:00
readingsEndUpdate ( $ hash , 1 ) ;
if ( $ hash == $ dhash ) {
2017-01-17 05:18:25 +00:00
2020-01-08 22:24:01 +00:00
NUKIBridge_ResponseProcessing ( $ hash , $ json , $ param - > { endpoint } ) ;
2016-09-27 11:37:19 +00:00
} else {
2020-01-08 22:24:01 +00:00
my $ decode_json = eval { decode_json ( $ json ) } ;
if ( $@ ) {
Log3 $ name , 3 , "NUKIBridge ($name) - JSON error while request: $@" ;
return ;
}
$ decode_json - > { nukiId } = $ param - > { nukiId } ;
$ json = encode_json ( $ decode_json ) ;
2020-01-08 15:30:42 +00:00
Dispatch ( $ hash , $ json , undef ) ;
2016-09-27 11:37:19 +00:00
}
2016-09-28 11:57:32 +00:00
2020-01-08 15:30:42 +00:00
2016-09-28 11:57:32 +00:00
return undef ;
2016-09-27 11:37:19 +00:00
}
2016-11-03 16:58:01 +00:00
sub NUKIBridge_ResponseProcessing ($$$) {
2016-09-27 11:37:19 +00:00
2016-11-03 16:58:01 +00:00
my ( $ hash , $ json , $ path ) = @ _ ;
2016-09-27 11:37:19 +00:00
my $ name = $ hash - > { NAME } ;
my $ decode_json ;
2017-01-04 12:44:06 +00:00
if ( ! $ json ) {
Log3 $ name , 3 , "NUKIBridge ($name) - empty answer received" ;
return undef ;
} elsif ( $ json =~ m 'HTTP/1.1 200 OK' ) {
Log3 $ name , 4 , "NUKIBridge ($name) - empty answer received" ;
return undef ;
} elsif ( $ json !~ m/^[\[{].*[}\]]$/ ) {
Log3 $ name , 3 , "NUKIBridge ($name) - invalid json detected: $json" ;
return "NUKIBridge ($name) - invalid json detected: $json" ;
}
2018-02-27 10:25:20 +00:00
2018-03-19 09:45:38 +00:00
$ decode_json = eval { decode_json ( $ json ) } ;
2018-02-27 10:25:20 +00:00
if ( $@ ) {
Log3 $ name , 3 , "NUKIBridge ($name) - JSON error while request: $@" ;
return ;
}
2016-09-27 11:37:19 +00:00
2017-01-10 20:02:39 +00:00
if ( ref ( $ decode_json ) eq "ARRAY" and scalar ( @ { $ decode_json } ) > 0 and $ path eq "list" ) {
2020-01-08 12:26:22 +00:00
my @ buffer = split ( '\[' , $ json ) ;
my ( $ json , $ tail ) = NUKIBridge_ParseJSON ( $ hash , $ buffer [ 1 ] ) ;
while ( $ json ) {
Log3 $ name , 5 ,
"NUKIBridge ($name) - Decoding JSON message. Length: "
. length ( $ json )
. " Content: "
. $ json ;
Log3 $ name , 5 ,
"NUKIBridge ($name) - Vor Sub: Laenge JSON: "
. length ( $ json )
. " Content: "
. $ json
. " Tail: "
. $ tail ;
Dispatch ( $ hash , $ json , undef )
unless ( not defined ( $ tail ) and not ( $ tail ) ) ;
( $ json , $ tail ) = NUKIBridge_ParseJSON ( $ hash , $ tail ) ;
Log3 $ name , 5 ,
"NUKIBridge ($name) - Nach Sub: Laenge JSON: "
. length ( $ json )
. " Content: "
. $ json
. " Tail: "
. $ tail ;
}
2020-01-08 15:30:42 +00:00
# NUKIBridge_Write($hash,"info",undef,undef,undef)
2020-01-08 12:26:22 +00:00
# if( !IsDisabled($name) );
2016-11-03 16:58:01 +00:00
}
elsif ( $ path eq "info" ) {
2017-01-07 08:31:09 +00:00
readingsBeginUpdate ( $ hash ) ;
readingsBulkUpdate ( $ hash , "state" , "connected" ) ;
Log3 $ name , 5 , "NUKIBridge ($name) - Bridge ist online" ;
readingsEndUpdate ( $ hash , 1 ) ;
$ hash - > { helper } { aliveCount } = 0 ;
2016-11-03 16:58:01 +00:00
NUKIBridge_InfoProcessing ( $ hash , $ decode_json ) ;
2016-09-27 11:37:19 +00:00
} else {
2020-01-08 12:26:22 +00:00
Log3 $ name , 5 , " NUKIBridge ( $ name ) - Rückgabe Path nicht korrekt:
$ json " ;
2016-11-03 16:58:01 +00:00
return ;
2016-09-27 11:37:19 +00:00
}
2016-09-28 11:57:32 +00:00
return undef ;
2016-09-27 11:37:19 +00:00
}
2019-12-17 20:49:21 +00:00
sub NUKIBridge_CGI () {
my ( $ request ) = @ _ ;
2020-01-08 22:24:01 +00:00
2019-12-17 20:49:21 +00:00
my $ hash ;
my $ name ;
2020-01-08 22:24:01 +00:00
while ( my ( $ key , $ value ) = each % { $ modules { NUKIBridge } { defptr } } ) {
$ hash = $ modules { NUKIBridge } { defptr } { $ key } ;
$ name = $ hash - > { NAME } ;
}
return "NUKIBridge WEBHOOK - No IODev found"
unless ( defined ( $ hash ) and defined ( $ name ) ) ;
2019-12-17 20:49:21 +00:00
2020-01-08 22:24:01 +00:00
my $ json = ( split ( "&" , $ request , 2 ) ) [ 1 ] ;
2019-12-17 20:49:21 +00:00
if ( ! $ json ) {
2020-01-08 22:24:01 +00:00
Log3 $ name , 3 , "NUKIBridge WEBHOOK ($name) - empty message received" ;
2019-12-17 20:49:21 +00:00
return undef ;
} elsif ( $ json =~ m 'HTTP/1.1 200 OK' ) {
2020-01-08 22:24:01 +00:00
Log3 $ name , 4 , "NUKIBridge WEBHOOK ($name) - empty answer received" ;
2019-12-17 20:49:21 +00:00
return undef ;
} elsif ( $ json !~ m/^[\[{].*[}\]]$/ ) {
2020-01-08 22:24:01 +00:00
Log3 $ name , 3 , "NUKIBridge WEBHOOK ($name) - invalid json detected: $json" ;
return "NUKIBridge WEBHOOK ($name) - invalid json detected: $json" ;
2019-12-17 20:49:21 +00:00
}
2020-01-08 22:24:01 +00:00
Log3 $ name , 5 , "NUKIBridge WEBHOOK ($name) - Webhook received with JSON: $json" ;
# my $decode_json = eval{decode_json($json)};
# if($@){
# Log3 $name, 3, "NUKIBridge WEBHOOK ($name) - JSON error while request: $@";
# return;
# }
if ( $ json =~ m/^\{.*\}$/ ) {
2019-12-21 20:52:18 +00:00
$ hash - > { WEBHOOK_COUNTER } + + ;
$ hash - > { WEBHOOK_LAST } = TimeNow ( ) ;
2019-12-17 20:49:21 +00:00
2020-01-08 22:24:01 +00:00
Log3 $ name , 4 , " NUKIBridge WEBHOOK ( $ name ) - Received webhook for
2020-01-08 12:26:22 +00:00
matching NukiId at device $ name " ;
2020-01-08 22:24:01 +00:00
Dispatch ( $ hash , $ json , undef ) ;
2019-12-17 20:49:21 +00:00
return ( undef , undef ) ;
}
# no data received
else {
2020-01-08 22:24:01 +00:00
Log3 $ name , 4 , "NUKIBridge WEBHOOK - received malformed request\n$request" ;
2019-12-17 20:49:21 +00:00
}
return ( "text/plain; charset=utf-8" , "Call failure: " . $ request ) ;
}
2016-09-27 11:37:19 +00:00
sub NUKIBridge_Autocreate ($$;$) {
my ( $ hash , $ decode_json , $ force ) = @ _ ;
my $ name = $ hash - > { NAME } ;
if ( ! $ force ) {
foreach my $ d ( keys % defs ) {
next if ( $ defs { $ d } { TYPE } ne "autocreate" ) ;
return undef if ( AttrVal ( $ defs { $ d } { NAME } , "disable" , undef ) ) ;
}
}
my $ autocreated = 0 ;
my $ nukiSmartlock ;
my $ nukiId ;
2019-12-21 20:52:18 +00:00
my $ nukiType ;
2016-09-27 11:37:19 +00:00
my $ nukiName ;
readingsBeginUpdate ( $ hash ) ;
foreach $ nukiSmartlock ( @ { $ decode_json } ) {
$ nukiId = $ nukiSmartlock - > { nukiId } ;
2019-12-21 20:52:18 +00:00
$ nukiType = $ nukiSmartlock - > { deviceType } ;
2016-09-27 11:37:19 +00:00
$ nukiName = $ nukiSmartlock - > { name } ;
my $ code = $ name . "-" . $ nukiId ;
if ( defined ( $ modules { NUKIDevice } { defptr } { $ code } ) ) {
2020-01-08 12:26:22 +00:00
Log3 $ name , 3 , " NUKIDevice ( $ name ) - NukiId '$nukiId' already
defined as '$modules{NUKIDevice}{defptr}{$code}->{NAME}' " ;
2016-09-27 11:37:19 +00:00
next ;
}
my $ devname = "NUKIDevice" . $ nukiId ;
2019-12-21 20:52:18 +00:00
my $ define = "$devname NUKIDevice $nukiId IODev=$name $nukiType" ;
2020-01-08 12:26:22 +00:00
Log3 $ name , 3 , " NUKIDevice ( $ name ) - create new device '$devname' for
address '$nukiId' " ;
2016-09-27 11:37:19 +00:00
my $ cmdret = CommandDefine ( undef , $ define ) ;
if ( $ cmdret ) {
2020-01-08 12:26:22 +00:00
Log3 $ name , 3 , " NUKIDevice ( $ name ) - Autocreate: An error occurred
while creating device for nukiId '$nukiId' : $ cmdret " ;
2016-09-27 11:37:19 +00:00
} else {
$ cmdret = CommandAttr ( undef , "$devname alias $nukiName" ) ;
$ cmdret = CommandAttr ( undef , "$devname room NUKI" ) ;
$ cmdret = CommandAttr ( undef , "$devname IODev $name" ) ;
}
$ defs { $ devname } { helper } { fromAutocreate } = 1 ;
readingsBulkUpdate ( $ hash , "${autocreated}_nukiId" , $ nukiId ) ;
readingsBulkUpdate ( $ hash , "${autocreated}_name" , $ nukiName ) ;
$ autocreated + + ;
2016-09-27 22:21:44 +00:00
readingsBulkUpdate ( $ hash , "smartlockCount" , $ autocreated ) ;
2016-09-27 11:37:19 +00:00
}
readingsEndUpdate ( $ hash , 1 ) ;
if ( $ autocreated ) {
2016-11-03 16:58:01 +00:00
Log3 $ name , 2 , "NUKIDevice ($name) - autocreated $autocreated devices" ;
2016-09-27 11:37:19 +00:00
CommandSave ( undef , undef ) if ( AttrVal ( "autocreate" , "autosave" , 1 ) ) ;
}
return "created $autocreated devices" ;
}
2016-11-03 16:58:01 +00:00
sub NUKIBridge_InfoProcessing ($$) {
my ( $ hash , $ decode_json ) = @ _ ;
my $ name = $ hash - > { NAME } ;
2017-01-17 05:18:25 +00:00
my $ nukiId ;
my $ scanResults ;
my % response_hash ;
my $ dname ;
my $ dhash ;
2016-11-03 16:58:01 +00:00
my % bridgeType = (
'1' = > 'Hardware' ,
'2' = > 'Software'
) ;
readingsBeginUpdate ( $ hash ) ;
2016-12-07 10:57:33 +00:00
readingsBulkUpdate ( $ hash , "appVersion" , $ decode_json - > { versions } - > { appVersion } ) ;
readingsBulkUpdate ( $ hash , "firmwareVersion" , $ decode_json - > { versions } - > { firmwareVersion } ) ;
readingsBulkUpdate ( $ hash , "wifiFirmwareVersion" , $ decode_json - > { versions } - > { wifiFirmwareVersion } ) ;
2016-11-03 16:58:01 +00:00
readingsBulkUpdate ( $ hash , "bridgeType" , $ bridgeType { $ decode_json - > { bridgeType } } ) ;
readingsBulkUpdate ( $ hash , "hardwareId" , $ decode_json - > { ids } { hardwareId } ) ;
readingsBulkUpdate ( $ hash , "serverId" , $ decode_json - > { ids } { serverId } ) ;
readingsBulkUpdate ( $ hash , "uptime" , $ decode_json - > { uptime } ) ;
readingsBulkUpdate ( $ hash , "currentTime" , $ decode_json - > { currentTime } ) ;
readingsBulkUpdate ( $ hash , "serverConnected" , $ decode_json - > { serverConnected } ) ;
readingsEndUpdate ( $ hash , 1 ) ;
2017-01-17 05:18:25 +00:00
foreach $ scanResults ( @ { $ decode_json - > { scanResults } } ) {
if ( ref ( $ scanResults ) eq "HASH" ) {
if ( defined ( $ modules { NUKIDevice } { defptr } ) ) {
while ( my ( $ key , $ value ) = each % { $ modules { NUKIDevice } { defptr } } ) {
$ dhash = $ modules { NUKIDevice } { defptr } { $ key } ;
$ dname = $ dhash - > { NAME } ;
$ nukiId = InternalVal ( $ dname , "NUKIID" , undef ) ;
next if ( ! $ nukiId or $ nukiId ne $ scanResults - > { nukiId } ) ;
Log3 $ name , 4 , "NUKIDevice ($dname) - Received scanResults for matching NukiID $nukiId at device $dname" ;
% response_hash = ( 'name' = > $ scanResults - > { name } , 'rssi' = > $ scanResults - > { rssi } , 'paired' = > $ scanResults - > { paired } ) ;
2020-01-08 12:26:22 +00:00
2017-01-17 05:18:25 +00:00
NUKIDevice_Parse ( $ dhash , encode_json \ % response_hash ) ;
}
}
}
}
2016-11-03 16:58:01 +00:00
}
2016-10-30 21:24:52 +00:00
sub NUKIBridge_getLogfile ($) {
my ( $ hash ) = @ _ ;
my $ name = $ hash - > { NAME } ;
2016-11-03 16:58:01 +00:00
my $ decode_json = NUKIBridge_CallBlocking ( $ hash , "log" , undef ) ;
2016-10-30 21:24:52 +00:00
2017-01-10 20:02:39 +00:00
Log3 $ name , 4 , "NUKIBridge ($name) - Log data are collected and processed" ;
2016-12-10 17:47:56 +00:00
2016-10-30 21:24:52 +00:00
if ( ref ( $ decode_json ) eq "ARRAY" and scalar ( @ { $ decode_json } ) > 0 ) {
2017-01-10 20:02:39 +00:00
Log3 $ name , 4 , "NUKIBridge ($name) - created Table with log file" ;
2016-10-30 21:24:52 +00:00
my $ ret = '<html><table width=100%><tr><td>' ;
$ ret . = '<table class="block wide">' ;
2016-12-18 12:21:09 +00:00
2016-10-30 21:24:52 +00:00
foreach my $ logs ( @ { $ decode_json } ) {
2016-12-18 12:21:09 +00:00
$ ret . = '<tr class="odd">' ;
2016-12-18 20:05:14 +00:00
if ( $ logs - > { timestamp } ) {
$ ret . = "<td><b>timestamp:</b> </td>" ;
$ ret . = "<td>$logs->{timestamp}</td>" ;
$ ret . = '<td> </td>' ;
}
if ( $ logs - > { type } ) {
$ ret . = "<td><b>type:</b> </td>" ;
$ ret . = "<td>$logs->{type}</td>" ;
$ ret . = '<td> </td>' ;
}
2016-12-18 12:21:09 +00:00
foreach my $ d ( reverse sort keys % { $ logs } ) {
2016-12-18 20:05:14 +00:00
next if ( $ d eq "type" ) ;
next if ( $ d eq "timestamp" ) ;
2016-12-18 12:21:09 +00:00
$ ret . = "<td><b>$d:</b> </td>" ;
$ ret . = "<td>$logs->{$d}</td>" ;
$ ret . = '<td> </td>' ;
}
2016-12-17 19:47:58 +00:00
2016-10-30 21:24:52 +00:00
$ ret . = '</tr>' ;
}
$ ret . = '</table></td></tr>' ;
$ ret . = '</table></html>' ;
return $ ret ;
}
}
2016-12-12 13:23:51 +00:00
sub NUKIBridge_getCallbackList ($) {
my ( $ hash ) = @ _ ;
my $ name = $ hash - > { NAME } ;
my $ decode_json = NUKIBridge_CallBlocking ( $ hash , "callback/list" , undef ) ;
2019-02-12 18:45:16 +00:00
return
unless ( ref ( $ decode_json ) eq 'HASH' ) ;
2016-12-12 13:23:51 +00:00
2020-01-08 12:26:22 +00:00
Log3 $ name , 4 , " NUKIBridge ( $ name ) - Callback data is collected and
processed " ;
2016-12-12 13:23:51 +00:00
2020-01-08 12:26:22 +00:00
if ( ref ( $ decode_json - > { callbacks } ) eq "ARRAY" and
scalar ( @ { $ decode_json - > { callbacks } } ) > 0 ) {
2017-01-10 20:02:39 +00:00
Log3 $ name , 4 , "NUKIBridge ($name) - created Table with log file" ;
2016-12-12 13:23:51 +00:00
my $ ret = '<html><table width=100%><tr><td>' ;
$ ret . = '<table class="block wide">' ;
$ ret . = '<tr class="odd">' ;
$ ret . = "<td><b>Callback-ID</b></td>" ;
$ ret . = "<td> </td>" ;
$ ret . = "<td><b>Callback-URL</b></td>" ;
$ ret . = '</tr>' ;
foreach my $ cb ( @ { $ decode_json - > { callbacks } } ) {
$ ret . = "<td>$cb->{id}</td>" ;
$ ret . = "<td> </td>" ;
$ ret . = "<td>$cb->{url}</td>" ;
$ ret . = '</tr>' ;
}
$ ret . = '</table></td></tr>' ;
$ ret . = '</table></html>' ;
return $ ret ;
}
2017-01-10 20:02:39 +00:00
return "No callback data available or error during processing" ;
2016-12-12 13:23:51 +00:00
}
2020-01-08 22:24:01 +00:00
sub NUKIBridge_CallBlocking ($@) {
2016-10-30 21:24:52 +00:00
2016-11-03 16:58:01 +00:00
my ( $ hash , $ path , $ obj ) = @ _ ;
2016-10-30 21:24:52 +00:00
my $ name = $ hash - > { NAME } ;
my $ host = $ hash - > { HOST } ;
my $ port = $ hash - > { PORT } ;
my $ token = $ hash - > { TOKEN } ;
2016-12-10 17:47:56 +00:00
2016-10-30 21:24:52 +00:00
my $ url = "http://" . $ hash - > { HOST } . ":" . $ port ;
$ url . = "/" . $ path if ( defined $ path ) ;
$ url . = "?token=" . $ token if ( defined ( $ token ) ) ;
2016-12-12 13:23:51 +00:00
$ url . = "&" . $ obj if ( defined ( $ obj ) ) ;
2016-10-30 21:24:52 +00:00
my ( $ err , $ data ) = HttpUtils_BlockingGet ( {
url = > $ url ,
2016-12-10 17:47:56 +00:00
timeout = > 3 ,
2016-10-30 21:24:52 +00:00
method = > "GET" ,
header = > "Content-Type: application/json" ,
} ) ;
2016-12-17 19:47:58 +00:00
2016-10-30 21:24:52 +00:00
if ( ! $ data ) {
2016-12-12 13:23:51 +00:00
Log3 $ name , 3 , "NUKIDevice ($name) - empty answer received for $url" ;
return undef ;
2016-10-30 21:24:52 +00:00
} elsif ( $ data =~ m 'HTTP/1.1 200 OK' ) {
2016-12-12 13:23:51 +00:00
Log3 $ name , 4 , "NUKIDevice ($name) - empty answer received for $url" ;
return undef ;
} elsif ( $ data !~ m/^[\[{].*[}\]]$/ and $ path ne "log" ) {
Log3 $ name , 3 , "NUKIDevice ($name) - invalid json detected for $url: $data" ;
return "NUKIDevice ($name) - invalid json detected for $url: $data" ;
2016-10-30 21:24:52 +00:00
}
2018-02-27 10:25:20 +00:00
my $ decode_json = eval { decode_json ( $ data ) } ;
if ( $@ ) {
Log3 $ name , 3 , "NUKIBridge ($name) - JSON error while request: $@" ;
return ;
}
2016-12-12 13:23:51 +00:00
2016-10-30 21:24:52 +00:00
return undef if ( ! $ decode_json ) ;
2016-12-12 13:23:51 +00:00
Log3 $ name , 5 , "NUKIBridge ($name) - Data: $data" ;
2017-01-10 20:02:39 +00:00
Log3 $ name , 4 , "NUKIBridge ($name) - Blocking HTTP Query finished" ;
2016-10-30 21:24:52 +00:00
return ( $ decode_json ) ;
}
2020-01-08 12:26:22 +00:00
sub NUKIBridge_ParseJSON ($$) {
my ( $ hash , $ buffer ) = @ _ ;
my $ name = $ hash - > { NAME } ;
my $ open = 0 ;
my $ close = 0 ;
my $ msg = '' ;
my $ tail = '' ;
if ( $ buffer ) {
foreach my $ c ( split // , $ buffer ) {
if ( $ open == $ close and $ open > 0 ) {
$ tail . = $ c ;
Log3 $ name , 5 ,
"NUKIBridge ($name) - $open == $close and $open > 0" ;
}
elsif ( ( $ open == $ close ) and ( $ c ne '{' ) ) {
Log3 $ name , 5 ,
"NUKIBridge ($name) - Garbage character before message: "
. $ c ;
}
else {
if ( $ c eq '{' ) {
$ open + + ;
}
elsif ( $ c eq '}' ) {
$ close + + ;
}
$ msg . = $ c ;
}
}
if ( $ open != $ close ) {
$ tail = $ msg ;
$ msg = '' ;
}
}
Log3 $ name , 5 ,
"NUKIBridge ($name) - return msg: $msg and tail: $tail" ;
return ( $ msg , $ tail ) ;
}
2016-10-30 21:24:52 +00:00
2017-01-17 05:18:25 +00:00
2016-09-27 11:37:19 +00:00
1 ;
= pod
2016-10-10 10:14:16 +00:00
= item device
2016-10-22 15:00:29 +00:00
= item summary Modul to control the Nuki Smartlock ' s over the Nuki Bridge .
2016-10-10 10:14:16 +00:00
= item summary_DE Modul zur Steuerung des Nuki Smartlock über die Nuki Bridge .
2016-09-27 11:37:19 +00:00
= begin html
2016-12-18 20:17:33 +00:00
2016-10-10 10:14:16 +00:00
< a name = "NUKIBridge" > </a>
<h3> NUKIBridge </h3>
2016-09-27 11:37:19 +00:00
<ul>
2016-10-11 07:11:43 +00:00
<u> <b> NUKIBridge - controls the Nuki Smartlock over the Nuki Bridge </b> </u>
<br>
The Nuki Bridge module connects FHEM to the Nuki Bridge and then reads all the smartlocks available on the bridge . Furthermore , the detected Smartlocks are automatically created as independent devices .
<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>
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> 0 _nukiId - ID of the first found Nuki Smartlock </li>
<li> 0 _name - Name of the first found Nuki Smartlock </li>
<li> smartlockCount - number of all found Smartlocks </li>
<li> bridgeAPI - API Version of bridge </li>
2016-12-18 12:21:09 +00:00
<li> bridgeType - Hardware bridge / Software bridge</ li >
<li> currentTime - 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> uptime - Uptime of the bridge in seconds </li>
<li> wifiFirmwareVersion - Version of the WiFi modules firmware </li>
2016-10-11 07:11:43 +00:00
<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> autocreate - Prompts to re - read all Smartlocks from the bridge and if not already present in FHEM , create the autimatic . </li>
2016-12-18 12:21:09 +00:00
<li> callbackRemove - Removes a previously added callback </li>
2017-01-19 20:07:38 +00:00
<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>
2016-12-18 12:21:09 +00:00
<li> info - Returns all Smart Locks in range and some device information of the bridge itself </li>
2017-01-19 20:07:38 +00:00
<li> reboot - reboots the bridge ( only hardwarebridge ) </li>
2016-12-18 12:21:09 +00:00
<br>
</ul>
<br> <br>
< a name = "NUKIBridgeget" > </a>
<b> Get </b>
<ul>
<li> callbackList - List of register url callbacks . The Bridge register up to 3 url callbacks . </li>
<li> logFile - Retrieves the log of the Bridge </li>
2016-10-11 07:11:43 +00:00
<br>
</ul>
<br> <br>
< a name = "NUKIBridgeattribut" > </a>
<b> Attributes </b>
<ul>
<li> disable - disables the Nuki Bridge </li>
2019-12-17 20:49:21 +00:00
<li> webhookFWinstance - Webinstanz of the Callback </li>
<li> webhookHttpHostname - IP or FQDN of the FHEM Server Callback </li>
2016-10-11 07:11:43 +00:00
<br>
</ul>
2016-09-27 11:37:19 +00:00
</ul>
= end html
= begin html_DE
2016-10-10 10:14:16 +00:00
< a name = "NUKIBridge" > </a>
<h3> NUKIBridge </h3>
2016-09-27 11:37:19 +00:00
<ul>
2016-10-10 10:14:16 +00:00
<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ü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> 0 _nukiId - ID des ersten gefundenen Nuki Smartlocks </li>
<li> 0 _name - Name des ersten gefunden Nuki Smartlocks </li>
<li> smartlockCount - Anzahl aller gefundenen Smartlock </li>
2016-10-11 07:11:43 +00:00
<li> bridgeAPI - API Version der Bridge </li>
2016-12-17 19:47:58 +00:00
<li> bridgeType - Hardware oder Software /App Bridge</ li >
<li> currentTime - 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> uptime - Uptime der Bridge in Sekunden </li>
<li> wifiFirmwareVersion - Firmwareversion des Wifi Modules der Bridge </li>
2016-10-10 10:14:16 +00:00
<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> autocreate - Veranlasst ein erneutes Einlesen aller Smartlocks von der Bridge und falls noch nicht in FHEM vorhanden das autimatische anlegen . </li>
2016-12-17 19:47:58 +00:00
<li> callbackRemove - Löschen einer Callback Instanz auf der Bridge . Die Instanz ID kann mittels get callbackList ermittelt werden </li>
<li> clearLog - lö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 über die Bridge </li>
<li> reboot - veranlä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 . Die Bridge nimmt maximal 3 auf . </li>
<li> logFile - Zeigt das Logfile der Bridge an </li>
2016-10-10 10:14:16 +00:00
<br>
</ul>
<br> <br>
< a name = "NUKIBridgeattribut" > </a>
<b> Attribute </b>
<ul>
<li> disable - deaktiviert die Nuki Bridge </li>
2019-12-17 20:49:21 +00:00
<li> webhookFWinstance - zu verwendene Webinstanz für den Callbackaufruf </li>
<li> webhookHttpHostname - IP oder FQDN vom FHEM Server für den Callbackaufruf </li>
2016-10-10 10:14:16 +00:00
<br>
</ul>
2016-09-27 11:37:19 +00:00
</ul>
= end html_DE
2016-12-10 17:47:56 +00:00
= cut