You can use the socket.http to build your HTTP Requests, and in case youâre expecting specific information from these devices, use the ltn12 module to sink the response data into a table. For example:
local http = require('socket.http')
local ltn12 = require("ltn12")
local res_payload = {}
local _, code = http.request({
url = '192.168.x.xxx',
sink = ltn12.sink.table(res_payload),
method='GET'
})
print(table.concat(json_payload))
Hi all, I am making progress in my quest to replace my HubAction groovy based DTH with an Edge Driver.
I am trying to make an Http call to the server but get the following error.
Http Response = [string âsocketâ]:1301: Permission Denied
Any thoughts?
I am using the following code in the command handler
local res_payload = {}
local _, code = http.request({
url = âurl = âhttp://192.168.188.121:80/api/callAction?deviceID=101&name=turnOnââ,
sink = ltn12.sink.table(res_payload),
method=âGETâ
})
log.info("Http Response = ", code)
print(table.concat(res_payload))
Some of my servers require Basic Authentication to access their resources.
From what I read the encoded username and password needs to be included in the http request headers. Something like this:
headers = { authentication = âBasic " ⌠(mime.b64(username âŚâ:" ⌠password)) }
However when I require the mine library like this
local mime = require(âmimeâ)
I get the following error:
Lua: runtime error: [string âinit.luaâ]:12: Module âmimeâ not found
Is the mime library missing from the smartthings environment or is there another way?
Is this a server youâre running on your computer? Iâd like to replicate the issue and it would be awesome if you could give me a few details on your environment.
UPDATE
@Tim99 Reviewing your implementation I just realized that youâre setting your authorization heather as it would work on other libraries (such as axios), hence, try passing it as follows:
LIFT OFF! @erickv thanks very much for pointing that out. I have now a fully working ON/OFF/SetLevel/SetColor Edge Driver using the http.request with Basic Authorization to remotely call my Fibaro Home Centre lighting Subsystem. Here is the code which may be useful for others.
CALL TO ROUTINE TO SWITCH ON LIGHT
local success, responseBody = command_handler.send_lan_command(
âhttp://192.168.188.121â,
âGETâ,
âapi/callAction?deviceID=101&name=turnOnâ,
{})
HTTP CALL FUNCTION
function command_handler.send_lan_command(url, method, path, body)
local dest_url = urlâŚâ/ââŚpath
local res_body = {}
local username = âxxxxxxâ
local password = âxxxxxxxxxxxxâ
â HTTP Request
local _, code = http.request({
method=method,
url=dest_url,
sink=ltn12.sink.table(res_body),
headers={
[âContent-Typeâ] = âapplication/x-www-urlencodedâ,
[âAuthorizationâ] = 'Basic â ⌠(base64.encode(username ⌠â:â ⌠password ))
}})
log.info(âcode=â, code)
â Handle response
if code == 200 or code == 202 then
return true, res_body
end
return false, nil
end
Iâm glad that youâre now able to interact with your Smart Home environment through drivers.
Remember that if you want to share your driver with the community, you can distribute a shared channel so others can install your driver (more info here).
My ST Edge driver is now working just fine. I can turn lights on & off in the Fibaro lighting sub-system, from Smartthings.
Next I would like to implement inbound commands into Smartthings from the lighting sub-system.
I am using the server code below from the lightbulb-lan-esp8266 sample as a starting point.
What is the Http.request call the Lighting sub-system needs to make to execute code in my edge driver.
Iâm trying a POST to ttp://192.168.188.22:39500/push-state with no autthorization at the moment. I get a code 202 returned, but no messages from live logging. Any thoughts?
local lux = require(âluxureâ)
local cosock = require(âcosockâ).socket
local json = require(âdkjsonâ)
local log = require(âlogâ)
local hub_server = {}
function hub_server.start(driver)
local server = lux.Server.new_with(cosock.tcp(), {env=âdebugâ})
â Register server
driver:register_channel_handler(server.sock, function ()
server:tick()
end)
â Endpoint
log.info(âSERVER ENDPOINTâ)
server:post(â/push-stateâ, function (req, res)
log.info("SERVER:POST")
local body = json.decode(req:get_body())
local device = driver:get_device_info(body.uuid)
if body.switch then
driver:on_off(device, body.switch)
elseif body.level then
driver:set_level(device, tonumber(body.level))
end
res:send('HTTP/1.1 200 OK')
end)
log.info(âSERVER LISTENâ)
server:listen()
driver.server = server
end
@Tim99 Maybe your Hub is receiving the request, but it isnât handling it properly⌠or the request information is not accurate.
Are you pointing to the PORT that the driver automatically defines for the server? you can log this as driver.server.port.
Also, if you followed the whole implementation, youâll notice that the IP and PORT are being shared with the device as soon as it gets integrated (see reference).
@erickv your are a star AGAIN!
The problem was that currently we cannot specify a Listener port. It is randomly chosen each time the driver is run. Which of course is a pain. Is this going to change in Production?
My device does not support SSDP, so my workaround plan is to retrieve the port being used via the variable driver.server.port, send this Port value to my device, which the device can use to POST back HTTP calls to the hub.
@Tim99 Awesome! Iâm very glad that youâre getting positive results with your integration.
Unfortunately, this is no going to change in the near future, because it isnât a huge blocker and can be addressed within or independently of discovery workflows (just as you did).
Do you mean a multi-child device approach based on the components that your board is supporting, for example, one device instance for the temperature sensor on your board and another one for the switches/relays?
If is not the case, can you please share more details about your implementation?
An Edge driver can control more than one type of device.
E.g. I have a single edge driver which creates and manages: simple switches, Dimmer switches, and RGBW lights.
You do this by having a different profile for each type of device the Edge Driver manages.
NB. All the devices created by the Edge driver and standalone devices. Not child devices.
hope this helps
Tim
what you can do is integrate your RaspberryPi as a bridge where the actual SSDP workflow operates, and then share the device metadata with the edge driver via HTTP.
The driver is still in development. It is a bridge between Smartthings and my Fibaro HomeCenter2 based Lighting sub-system.
The driver discovers all the lights connected to the Lighting Sub-system and creates an equivalent âTwinâ device in Smartthings. It supports Switches, Dimmers and RGBW devices.
Each has their own profile under the Edge profile directory. The appropriate profile is used to create a âTwinâ device in smartthings. The key code snippet for creating a switch is below.