Posts: 265
Threads: 39
Joined: Feb 2016
Reputation:
1
19.09.2018, 16:30
(This post was last modified: 19.09.2018, 16:35 by domotiqa .)
hello,
is there someone who already dealed with this interface with "hidden" ip api ?
I found someone who made a script:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
local VeluxDebug =
true
local programme =
"2"
local password =
"xxxYYYzzz"
local KLF_ip =
"192.168.yyy.zzz"
local params =
fibaro :
args ()
if (
params )
then
for k ,
v in ipairs (
params )
do
if (
v.programme )
then
programme =
v.programme
end
if (
v.adresseIP )
then
KLF_ip =
v.adresseIP
end
if (
v.password )
then
password =
v.password
end
end
end
local urlLogin =
'http://' ..
KLF_ip ..
'/api/v1/auth'
local urlLogout =
'http://' ..
KLF_ip ..
'/api/v1/auth'
local urlScenes =
'http://' ..
KLF_ip ..
'/api/v1/scenes'
local datasLogin =
'{"action":"login","params":{"password":"' ..
password ..
'"}}'
local datasLogout =
'{"action":"logout","params":{}}'
local datasAction =
'{"action":"run","params":{"id":"' ..
programme ..
'"}}'
if (
VeluxDebug )
then
fibaro :
debug (
"Démarrage de la scène avec les paramètres suivants" )
fibaro :
debug (
"adresse IP = " ..
KLF_ip )
fibaro :
debug (
"Password = " ..
password )
fibaro :
debug (
"Programme = " ..
programme )
fibaro :
debug (
datasAction )
end
local klf =
net.HTTPClient ()
klf :
request (
urlLogin , {
success =
function (
response )
if tonumber (
response.status ) ==
200 then
if (
VeluxDebug )
then
fibaro :
debug (
"Call for LOGON successfull" )
fibaro :
debug (
"Valeur de response" )
fibaro :
debug (
json.encode (
response ))
end
local temp =
json.encode (
response )
local token =
temp :
match (
'\\\"token\\\":\\\"(.+)\\\",\\\"result' )
token =
string.gsub (
token ,
'\\' ,
'' )
if (
VeluxDebug )
then
fibaro :
debug (
"Valeur du token : " ..
token )
end
klf :
request (
urlScenes , {
success =
function (
response )
if tonumber (
response.status ) ==
200 then
if (
VeluxDebug )
then
fibaro :
debug (
"Call for ACTION successful" )
fibaro :
debug (
"response\n" )
fibaro :
debug (
json.encode (
response ))
end
klf :
request (
urlLogout , {
success =
function (
response )
if tonumber (
response.status ) ==
200 then
if (
VeluxDebug )
then
fibaro :
debug (
"Call for LOGOUT successful" )
fibaro :
debug (
"response\n" )
fibaro :
debug (
json.encode (
response ))
end
else
if (
VeluxDebug )
then
fibaro :
debug (
"LOGOUT Failed : Status =" ..
response.status )
end
end
end ,
error =
function (
err )
print (
"Erreur de LOGOUT" )
print (
'error = ' ..
err )
end ,
options = {
method =
'POST' ,
headers = {
[
"content-type" ] =
'application/json, charset=utf-8' ,
[
"Authorization" ] =
"Bearer " ..
token ,
[
"Connection" ] =
'close' ,
},
data =
datasLogout
}
})
else
if (
VeluxDebug )
then
fibaro :
debug (
"RUN ACTION Failed : Status =" ..
response.status )
end
end
end ,
error =
function (
err )
print (
"Erreur lors du RUN ACTION" )
print (
'error =' ..
err )
end ,
options = {
method =
'POST' ,
headers = {
[
"content-type" ] =
'application/json, charset=utf-8' ,
[
"content-length" ] =
"34" ,
[
"Authorization" ] =
"Bearer " ..
token ,
[
"Connection" ] =
'Keep-Alive' ,
},
data =
datasAction
}
})
else
if (
VeluxDebug )
then
fibaro :
debug (
"Login Failed : Status =" ..
response.status )
end
end
end ,
error =
function (
err )
print (
"Erreur lors du LOGIN" )
print (
'error = ' ..
err )
end ,
options = {
method =
'POST' ,
headers = {
[
"content-type" ] =
'application/json, charset=utf-8' ,
[
"connection" ] =
'close' ,
},
data =
datasLogin
}
})
-----------
FRANCE SMARTHOME & SMARTBUILDING INTEGRATION
SE ECO EXPERT
Posts: 8138
Threads: 43
Joined: Jun 2015
Reputation:
472
This code can be rewritten to run on LM, this thread has some similar examples of HTTP requests:
https://forum.logicmachine.net/showthread.php?tid=993
Posts: 265
Threads: 39
Joined: Feb 2016
Reputation:
1
11.02.2019, 14:17
(This post was last modified: 11.02.2019, 14:23 by domotiqa .)
looks like Velux changed the API of the KLF200
https://velcdn.azureedge.net/~/media/com...er3-16.pdf
looks harder
an example
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
## ======================================================
##
Script pour demarrer une scene de la box Velux KLF-200
##
##
Version 0.1.1 -
Last update :
03.11.18 by Christian R.
## ======================================================
import ssl ,
socket ,
time ,
struct
from time import sleep
# ===============================================================================
#
Variables
# ===============================================================================
SCENE_ID =
1
KLF200_ADDRESS =
"192.168.0.12"
PASSWORD =
"Velux123"
PORT =
51200
LoopDelay =
1
# ===============================================================================
#
slip
# ===============================================================================
END =
b "\xC0" #
SLIP escape character as per RFC 1055
ESC =
b "\xDB" #
SLIP escape character as per RFC 1055
ESC_END =
b "\xDC" #
SLIP escape character as per RFC 1055
ESC_ESC =
b "\xDD" #
SLIP escape character as per RFC 1055
def slip_pack (
inputFrame ):
data =
inputFrame
data =
data.replace (
ESC ,
ESC +
ESC_ESC )
data =
data.replace (
END ,
ESC +
ESC_END )
return END +
data +
END
def slip_unpack (
inputFrame ):
data =
inputFrame
if (
data [
0 :
1 ]==
END and data [-
1 :]==
END ):
data =
data.replace (
ESC +
ESC_END ,
END )
data =
data.replace (
ESC +
ESC_ESC ,
ESC )
return data [
1 :-
1 ]
else :
print (
"Error: No SLIP frame!\n" )
return inputFrame #
error ->
return input
# ===============================================================================
#
toolbox
# ===============================================================================
def getIndex (
sourceDict ,
value ):
return (
k for k ,
v in sourceDict.items ()
if v ==
value ).
__next__ ()
def toHex (
s ):
return ":" .
join (
"{:02x}" .
format (
c )
for c in s )
# ===============================================================================
#
ActivateScene
# ===============================================================================
def process_connection (
conn ):
conn.settimeout (
10.0 ) #
10 sec
print (
"Send valid password" )
conn.write (
bytes (
ST_GW_PASSWORD_ENTER_REQ (
PASSWORD )))
print (
"Received: " ,
toHex (
slip_unpack (
conn.recv ())),
"\n" )
time.sleep (
LoopDelay )
print (
"Activate Scene with ID = " ,
SCENE_ID )
conn.write (
bytes (
ST_GW_ACTIVATE_SCENE_REQ (
bSceneID =
SCENE_ID )))
print (
"Received: " ,
toHex (
slip_unpack (
conn.recv ())))
def main ():
sock =
socket.socket (
socket.AF_INET )
sock.settimeout (
10.0 )
context =
ssl.SSLContext (
ssl.PROTOCOL_TLS )
context.check_hostname =
False
#
accept self-signed certificate
context.verify_mode =
ssl.CERT_NONE
conn =
context.wrap_socket (
sock ,
server_hostname =
KLF200_ADDRESS )
try :
conn.connect ((
KLF200_ADDRESS ,
PORT ))
process_connection (
conn )
except BaseException as e :
raise (
e )
finally :
conn.close ()
# ===============================================================================
#
klf200api
# ===============================================================================
GW_ACTIVATE_SCENE_REQ =
0x0412
GW_ACTIVATE_SCENE_CFM =
0x0413
GW_PASSWORD_ENTER_REQ =
0x3000
GW_PASSWORD_ENTER_CFM =
0x3001
dictPriorityLevel = {
0 :
'Human Protection' ,
1 :
'Environment Protection' ,
2 :
'User Level 1' ,
3 :
'User Level 2' ,
4 :
'Comfort Level 1' ,
5 :
'Comfort Level 2' ,
6 :
'Comfort Level 3' ,
7 :
'Comfort Level 4' ,
}
dictCommandOriginator = {
0x00 :
"LOCAL_USER" , # //
User pressing button locally on actuator
0x01 :
"USER" , # //
User Remote control causing action on actuator
0x02 :
"RAIN" , # //
Sensor
0x03 :
"TIMER" , # //
Sensor
0x04 :
"SECURITY" , # //
SCD controlling actuator
0x05 :
"UPS" , # //
UPS unit
0x06 :
"SFC" , # //
Smart Function Controller
0x07 :
"LSC" , # //
Lifestyle Scenario Controller
0x08 :
"SAAC" , # //
Stand Alone Automatic Controls
0x09 :
"WIND" , # //
Wind detection
0x10 :
"MYSELF" , # //
Used when an actuator decides to move by itself
0xFE :
"AUTOMATIC_CYCLE" , # //
Used in context with automatic cycle ;
0xFF :
"EMERGENCY" # //
Used in context with emergency or security commands ,
# // -
this command originator should never be disabled
}
dictVelocity = {
0 :
'DEFAULT' ,
1 :
'SILENT' ,
2 :
'FAST' ,
255 :
'VELOCITY_NOT_AVAILABLE' , #
Only used in status reply
}
# ===============================================================================
class ST_GW_FRAME :
def __init__ (
self ,
Command ):
self.DataLength =
0
self.Command =
Command
self.binary_output =
b "" ;
def __bytes__ (
self ):
self.binary_output =
struct.pack (
"BB" ,
0 ,
self.DataLength +
3 )
self.binary_output +=
struct.pack (
">H" ,
self.Command )
self.binary_output +=
self.pack_data ()
self.binary_output +=
struct.pack (
"B" ,
self.calc_crc ())
return slip_pack (
self.binary_output )
def calc_crc (
self ):
crc =
0
for sym in self.binary_output :
crc =
crc ^
int (
sym )
return crc
def pack_data (
self ):
return b ""
class ST_GW_ACTIVATE_SCENE_REQ (
ST_GW_FRAME ):
def __init__ (
self ,
wSessionID =
0x1234 ,
CommandOriginator =
'USER' ,
PriorityLevel =
'User Level 2' ,
bSceneID =
0 ,
Velocity =
'DEFAULT' ):
ST_GW_FRAME.__init__ (
self ,
GW_ACTIVATE_SCENE_REQ )
self.DataLength =
6
self.wSessionID =
wSessionID
self.bCommandOriginator =
getIndex (
dictCommandOriginator ,
CommandOriginator )
self.bPriorityLevel =
getIndex (
dictPriorityLevel ,
PriorityLevel )
self.bSceneID =
bSceneID
self.bVelocity =
getIndex (
dictVelocity ,
Velocity )
def pack_data (
self ):
ret =
struct.pack (
">H" ,
self.wSessionID )
ret +=
bytes ([
self.bCommandOriginator ])
ret +=
bytes ([
self.bPriorityLevel ])
ret +=
bytes ([
self.bSceneID ])
ret +=
bytes ([
self.bVelocity ])
return ret
class ST_GW_PASSWORD_ENTER_REQ (
ST_GW_FRAME ):
def __init__ (
self ,
Password ):
ST_GW_FRAME.__init__ (
self ,
GW_PASSWORD_ENTER_REQ )
self.DataLength =
32
self.Password =
Password
def pack_data (
self ):
binary_data =
bytes (
self.Password ,
encoding =
'ascii' )
binary_len =
len (
binary_data )
ret =
binary_data [:
self.DataLength if binary_len >
self.DataLength else binary_len ]
while binary_len <
self.DataLength :
ret +=
b '\x00'
binary_len =
binary_len +
1
return ret
# ===============================================================================
#
Start script
# ===============================================================================
main ()
print (
"Finished" )
-----------
FRANCE SMARTHOME & SMARTBUILDING INTEGRATION
SE ECO EXPERT
Posts: 8138
Threads: 43
Joined: Jun 2015
Reputation:
472
This is doable but quite hard to provide an working example without access to the device itself to test it.
Posts: 265
Threads: 39
Joined: Feb 2016
Reputation:
1
adminThis is doable but quite hard to provide an working example without access to the device itself to test it.
yes
can you provide at least exemple for the part with the initialisation:
GW_PASSWORD_ENTER_REQ( Last byte of Password byte array must be null terminated )
defaut password is
because in fact i only need, the authentification, then the command send
GW_COMMAND_SEND_REQ()
-----------
FRANCE SMARTHOME & SMARTBUILDING INTEGRATION
SE ECO EXPERT
Posts: 20
Threads: 4
Joined: Mar 2019
Reputation:
2
Hi,
A full API made by Chris Traeger is available for Node.js. It is compatible with the latest versions of the KLF200 firmware
This would probably be a good base to implement something in LM.
It is available at:
https://github.com/PLCHome/velux-klf200-api
Cheers.
Michel.
Posts: 119
Threads: 15
Joined: Nov 2019
Reputation:
6
Here you can download the
API documentation
The API password is the WLAN password of the KLF200
Posts: 14
Threads: 3
Joined: Feb 2021
Reputation:
1
15.07.2024, 16:48
(This post was last modified: 15.07.2024, 17:32 by kgroenhoej .)
(13.02.2019, 06:33) admin Wrote: This is doable but quite hard to provide an working example without access to the device itself to test it.
Yes - understandable.
The integration would be a big benefit for projects that include both KNX (LM) and Velux. But maybe Velux is not interested in helping with this integration now they have their own KNX-integration: DISK (Domex)
Posts: 457
Threads: 97
Joined: Jun 2015
Reputation:
6
16.07.2024, 06:06
(This post was last modified: 16.07.2024, 06:10 by gjniewenhuijse .)
Posts: 14
Threads: 3
Joined: Feb 2021
Reputation:
1
Even the “knx-lite” ABB-free@home have an integration:
ABB-free@home Velux Interface KLF 200
Somehow abb was able to get a Velux-developer-test-setup