-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
*adapted from danlogan9 gist https://gist.github.com/danlogan9/66b8ed43c1cb372e3811756a737397b2. * Updated the version dependency on hs-100 api 0.2.0
- Loading branch information
Aaron Paquette
committed
Dec 2, 2016
1 parent
58b4184
commit c1ff0d4
Showing
4 changed files
with
253 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
#1. put the files in a folder called hs-100 | ||
#2. sudo docker build -t hs-100:latest hs-100/. | ||
#3. run the container | ||
#4. sudo docker run -d -p 8083:8083 -v /etc/localtime:/etc/localtime:ro --restart=always --name hs-100 hs-100:latest | ||
# or | ||
#4. docker run -t -i -p 8083:8083 --entrypoint=/bin/bash --name hs-100 hs-100:latest | ||
|
||
FROM phusion/baseimage:latest | ||
|
||
CMD ["/sbin/my_init"] | ||
|
||
RUN apt-get -y update | ||
RUN apt-get install -y nodejs npm | ||
RUN apt-get install -y nano | ||
|
||
|
||
RUN npm install -g n | ||
RUN n stable | ||
|
||
COPY . /hs-100 | ||
RUN cd /hs-100; npm install | ||
|
||
|
||
EXPOSE 8083 | ||
|
||
CMD ["node", "/hs-100/hs100.js"] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/** | ||
* hs100.js | ||
* | ||
* Copyright 2016 Dan Logan | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except | ||
* in compliance with the License. You may obtain a copy of the License at: | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed | ||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License | ||
* for the specific language governing permissions and limitations under the License. | ||
* | ||
*/ | ||
|
||
var sock = require('net'); | ||
var http = require('http'); | ||
var url = require('url'); | ||
var hs100api = require('hs100-api'); | ||
|
||
const PORT = 8083; | ||
|
||
var server = http.createServer(onRequest); | ||
server.listen(PORT); | ||
console.log("The HS-100 controller has started"); | ||
|
||
function onRequest(request, response){ | ||
//var pathname = url.parse(request.url).pathname; | ||
var command = request.headers["x-hs100-command"]; | ||
var deviceIP = request.headers["x-hs100-ip"]; | ||
var hs100 = new hs100api({host:deviceIP}); | ||
var msg = ''; | ||
switch(command) { | ||
case "on": | ||
console.log("on"); | ||
msg = 'you turned ' + deviceIP + ' on'; | ||
hs100.setPowerState(true); | ||
response.end(msg); | ||
break; | ||
case "off": | ||
console.log("off"); | ||
msg = 'you turned ' + deviceIP + ' off'; | ||
hs100.setPowerState(false); | ||
response.end(msg); | ||
break; | ||
case "status": | ||
console.log("status"); | ||
console.log(deviceIP + ":" + command); | ||
var p = Promise.resolve(hs100.getPowerState()); | ||
p.then(function(data){ | ||
var state = ((data) ? "on" : "off"); | ||
msg = "you checked " + deviceIP + " status:" + state; | ||
response.setHeader("x-hs100-status", state); | ||
response.end(msg); | ||
}); | ||
break; | ||
default: | ||
response.end('hs100'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"name": "hs-100-api-bridge", | ||
"version": "1.0.0", | ||
"author": "none", | ||
"scripts": { | ||
}, | ||
"dependencies": { | ||
"hs100-api":"^0.2.0" | ||
}, | ||
"private":true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
/** | ||
* tplink-hs-100 | ||
* | ||
* Copyright 2016 Dan Logan | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except | ||
* in compliance with the License. You may obtain a copy of the License at: | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed | ||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License | ||
* for the specific language governing permissions and limitations under the License. | ||
* | ||
*/ | ||
|
||
metadata { | ||
definition (name: "tplink-hs-100", namespace: "danlogan9", author: "Dan Logan") { | ||
capability "Switch" | ||
capability "Refresh" | ||
capability "Polling" | ||
} | ||
|
||
simulator { | ||
// TODO: define status and reply messages here | ||
} | ||
|
||
tiles { | ||
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) { | ||
state "off", label: 'Off', action: "switch.on", | ||
icon: "st.switches.switch.off", backgroundColor: "#ffffff" | ||
state "on", label: 'On', action: "switch.off", | ||
icon: "st.switches.switch.on", backgroundColor: "#79b821" | ||
} | ||
|
||
standardTile("refresh", "capability.refresh", width: 1, height: 1, decoration: "flat") { | ||
state ("default", label:"Refresh", action:"refresh.refresh", icon:"st.secondary.refresh") | ||
} | ||
|
||
main("switch") | ||
details(["switch"]) | ||
} | ||
|
||
command "on" | ||
command "off" | ||
|
||
} | ||
|
||
preferences { | ||
input("outletIP", "text", title: "Outlet IP", required: true, displayDuringSetup: true) | ||
input("gatewayIP", "text", title: "Gateway IP", required: true, displayDuringSetup: true) | ||
input("gatewayPort", "text", title: "Gateway Port", required: true, displayDuringSetup: true) | ||
} | ||
|
||
def message(msg){ | ||
log.debug(msg) | ||
} | ||
|
||
// parse events into attributes | ||
def parse(String description) { | ||
//message("Parsing '${description}'") | ||
log.debug "parsing" | ||
def msg = parseLanMessage(description) | ||
|
||
def headersAsString = msg.header // => headers as a string | ||
def headerMap = msg.headers // => headers as a Map | ||
def body = msg.body // => request body as a string | ||
def status = msg.status // => http status code of the response | ||
def json = msg.json // => any JSON included in response body, as a data structure of lists and maps | ||
def xml = msg.xml // => any XML included in response body, as a document tree structure | ||
def data = msg.data // => either JSON or XML in response body (whichever is specified by content-type header in response) | ||
//message(msg.body) | ||
//message(headerAsString) | ||
|
||
//status = headerMap["x-hs100-status"] ?: "" | ||
//message("switch status: '${status}'") | ||
//if (status != "") { | ||
// sendEvent(name: "switch", value: status, isStateChange: true) | ||
//} | ||
|
||
//def uuid = UUID.randomUUID().toString() | ||
//device.deviceNetworkId = "tp_link_${uuid}" | ||
} | ||
|
||
def refresh(){ | ||
executeCommand("status") | ||
} | ||
|
||
// handle commands | ||
def on() { | ||
message("Executing 'on'") | ||
executeCommand("on") | ||
sendEvent(name: "switch", value: "on", isStateChange: true) | ||
} | ||
|
||
def off() { | ||
message("Executing 'off'") | ||
executeCommand("off") | ||
sendEvent(name: "switch", value: "off", isStateChange: true) | ||
} | ||
|
||
def hubActionResponse(response){ | ||
message("Executing 'hubActionResponse': '${device.deviceNetworkId}'") | ||
//message(response) | ||
|
||
def status = response.headers["x-hs100-status"] ?: "" | ||
message("switch status: '${status}'") | ||
if (status != "") { | ||
sendEvent(name: "switch", value: status, isStateChange: true) | ||
} | ||
|
||
} | ||
|
||
def poll(){ | ||
executeCommand("status") | ||
} | ||
|
||
private executeCommand(command){ | ||
|
||
def gatewayIPHex = convertIPtoHex(gatewayIP) | ||
def gatewayPortHex = convertPortToHex(gatewayPort) | ||
//device.deviceNetworkId = "$gatewayIPHex:$gatewayPortHex" | ||
message (device.deviceNetworkId) | ||
message ("gateway port: $gatewayIP:$gatewayPort") | ||
|
||
def headers = [:] | ||
headers.put("HOST", "$gatewayIP:$gatewayPort") | ||
headers.put("x-hs100-ip", outletIP) | ||
headers.put("x-hs100-command", command) | ||
|
||
//message("x-hs100-ip: '$outletIP'") | ||
//message("executeCommand: '${command}'") | ||
try { | ||
sendHubCommand(new physicalgraph.device.HubAction([ | ||
method: "GET", | ||
path: "/", | ||
headers: headers], | ||
device.deviceNetworkId, | ||
[callback: "hubActionResponse"] | ||
)) | ||
} catch (e) { | ||
message(e.message) | ||
} | ||
} | ||
|
||
private String convertIPtoHex(ipAddress) { | ||
String hex = ipAddress.tokenize( '.' ).collect { String.format( '%02x', it.toInteger() ) }.join() | ||
return hex | ||
} | ||
|
||
private String convertPortToHex(port) { | ||
String hexport = port.toString().format( '%04x', port.toInteger() ) | ||
return hexport | ||
} |