Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- * Copyright 2017 Chris Charles
- *
- * 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.
- *
- * Neo Hub Bridge (Parent Device of Neo Thermostat)
- *
- * Author: Chris Charles (cjcharles0)
- * Date: 2017-04-26
- */
- import groovy.json.JsonSlurper
- metadata {
- definition (name: "Neo Hub Bridge", namespace: "cjcharles0", author: "Chris Charles") {
- capability "Refresh"
- capability "Configuration"
- capability "Polling"
- command "getthermostats"
- command "removethermostats"
- command "childRequestingRefresh"
- command "updateThermostatInfo"
- command "testcommand"
- }
- simulator {
- }
- preferences {
- input("password", "password", title:"Password", required:false, displayDuringSetup:false)
- input("bridgeip", "string", title:"Neo Bridge IP Address", description: "e.g. 192.168.1.10", required: true, displayDuringSetup: true)
- input("neohubip", "string", title:"NeoHub IP Address", description: "e.g. 192.168.1.11", required: true, displayDuringSetup: true)
- input("prestatname", "string", title:"Add before stat name", description: "e.g. 'Thermostat' would give 'Thermostat Kitchen'", required: false, displayDuringSetup: true)
- input("poststatname", "string", title:"Add after stat name", description: "e.g. 'Thermostat' would give 'Kitchen Thermostat'", required: false, displayDuringSetup: true)
- }
- tiles (scale: 2){
- valueTile("lastcommand", "lastcommand", decoration: "flat", width: 6, height: 2) {
- state "lastcommand", label:'${currentValue}', icon: "st.Home.home2"
- }
- valueTile("stip", "stip", decoration: "flat", width: 2, height: 1) {
- state "stip", label:'ST IP Addr.\r\n${currentValue}'
- }
- valueTile("neoip", "neoip", decoration: "flat", width: 2, height: 1) {
- state "neoip", label:'Neohub IP Addr.\r\n${currentValue}'
- }
- valueTile("brip", "brip", decoration: "flat", width: 2, height: 1) {
- state "brip", label:'ESP Bridge IP Addr.\r\n${currentValue}'
- }
- standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 1, height: 1) {
- state "default", label:"Refresh Inf", action:"refresh", icon:"st.secondary.refresh"
- }
- standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat", width: 1, height: 1) {
- state "configure", label:'Bridge', action:"configure", icon:"st.secondary.configure"
- }
- standardTile("getthermostats", "device.getthermostats", inactiveLabel: false, decoration: "flat", width: 2, height: 1) {
- state "getthermostats", label:'Create Thermostat Devices', action:"getthermostats", icon: "st.unknown.zwave.remote-controller"
- }
- standardTile("removethermostats", "device.removethermostats", inactiveLabel: false, decoration: "flat", width: 2, height: 1) {
- state "removethermostats", label:'Remove Thermostat Devices', action:"removethermostats", icon: "st.samsung.da.washer_ic_cancel"
- }
- standardTile("testcommand", "device.testcommand", inactiveLabel: false, decoration: "flat", width: 2, height: 1) {
- state "testcommand", label:'Send Test Neohub command', action:"testcommand"
- }
- }
- main(["lastcommand"])
- details(["lastcommand",
- "stip", "neoip", "brip",
- "refresh", "configure", "getthermostats", "removethermostats",
- //"testcommand"
- ])
- }
- def testcommand(){
- log.debug "Getting firmware version"
- childAwayOff("neostatDownstairs")
- }
- def configure(){
- def cmds = []
- log.debug "Configuring NeoBridge"
- cmds << getAction("/config?ip_for_st=${device.hub.getDataValue("localIP")}&port_for_st=${device.hub.getDataValue("localSrvPortTCP")}&ip_for_neohub=${neohubip}&port_for_neohub=4242")
- return cmds
- }
- def refresh() {
- log.debug "refresh()"
- //SendEvents should be before any getAction, otherwise getAction does nothing
- sendEvent(name: "stip", value: device.hub.getDataValue("localIP")+" Port:"+device.hub.getDataValue("localSrvPortTCP"), displayed: false)
- sendEvent(name: "neoip", value: neohubip + " Port:4242", displayed: false)
- sendEvent(name: "brip", value: bridgeip + " Port:80", displayed: false)
- //Also refresh thermostats with the same command
- childRequestingRefresh()
- }
- def installed() {
- log.debug "installed()"
- //configure()
- }
- def uninstalled() {
- removethermostats()
- }
- def updated() {
- log.debug "updated()"
- configure()
- }
- def ping() {
- log.debug "ping()"
- getAction("/ping")
- }
- private getthermostats(){
- //Before sending request for thermostat list we should remove current thermostats
- def cmds = []
- removethermostats()
- log.debug "Requesting List of Thermostats"
- cmds << getAction("/neorelay?device=hubzonesetup&command={\"GET_ZONES\":0}")
- return cmds
- }
- private removethermostats(){
- log.debug "Removing Child Thermostats"
- getChildDevices()?.each {
- deleteChildDevice(it.deviceNetworkId)
- }
- }
- def childRequestingRefresh() {
- //Send Refresh command
- def cmds = []
- log.debug "Requesting refreshed info for all children"
- cmds << getAction("/neorelay?device=hubzonerefresh&command={\"INFO\":0}")
- return cmds
- }
- def childSetTemp(int temp, String dni) {
- //Send Child Set Temp command
- def cmds = []
- def deviceid = dni.replaceAll("neostat", "").replaceAll("-", " ")
- log.debug "Requesting ${temp} degrees for child ${deviceid}"
- cmds << getAction("/neorelay?device=${dni}&command={\"SET_TEMP\":[\"${temp}\", \"${deviceid}\"]}")
- return cmds
- }
- def childAwayOn(String dni) {
- //Send Child Away on command
- def cmds = []
- def deviceid = dni.replaceAll("neostat", "").replaceAll("-", " ")
- log.debug "Requesting away mode on for child ${deviceid}"
- cmds << getAction("/neorelay?device=${dni}&command={\"AWAY_ON\":\"${deviceid}\"}")
- return cmds
- }
- def childAwayOff(String dni) {
- //Send Child Away off command
- def cmds = []
- def deviceid = dni.replaceAll("neostat", "").replaceAll("-", " ")
- log.debug "Requesting away mode off for child ${deviceid}"
- cmds << getAction("/neorelay?device=${dni}&command={\"AWAY_OFF\":\"${deviceid}\"}")
- return cmds
- }
- def childHeat(String dni) {
- //Send Child Heat mode
- def cmds = []
- def deviceid = dni.replaceAll("neostat", "").replaceAll("-", " ")
- log.debug "Requesting heat mode for child ${deviceid}"
- cmds << getAction("/neorelay?device=${dni}&command={\"HEAT\":\"${deviceid}\"}")
- return cmds
- }
- def childHold(int temp, String id, int hours, int minutes, String dni) {
- //Send Child Hold command
- def cmds = []
- def deviceid = dni.replaceAll("neostat", "").replaceAll("-", " ")
- log.debug "Requesting Hold at ${temp} degrees for ${hours}h:${mins}m for child ${deviceid}"
- cmds << getAction("/neorelay?device=${dni}&command={\"HOLD\":[{\"temp\":\"${temp}\",\"id\":\"${id}\",\"hours\":\"${hours}\",\"minutes\":\"${minutes}\"}, \"${deviceid}\"]}")
- return cmds
- }
- def childBoostOn(int hours, int minutes, String dni) {
- //Send Child Boost On command
- def cmds = []
- def deviceid = dni.replaceAll("neostat", "").replaceAll("-", " ")
- log.debug "Requesting boost on for child ${deviceid}"
- cmds << getAction("/neorelay?device=${dni}&command={\"BOOST_ON\":[{\"hours\":\"${hours}\",\"minutes\":\"${minutes}\"}, \"${deviceid}\"]}")
- return cmds
- }
- def childBoostOff(int hours, int minutes, String dni) {
- //Send Child Boost On command
- def cmds = []
- def deviceid = dni.replaceAll("neostat", "").replaceAll("-", " ")
- log.debug "Requesting boost off for child ${deviceid}"
- cmds << getAction("/neorelay?device=${dni}&command={\"BOOST_OFF\":[{\"hours\":\"${hours}\",\"minutes\":\"${minutes}\"}, \"${deviceid}\"]}")
- return cmds
- }
- def childFrostOn(String dni) {
- //Send Child Frost On command
- def cmds = []
- def deviceid = dni.replaceAll("neostat", "").replaceAll("-", " ")
- log.debug "Requesting frost on for child ${deviceid}"
- cmds << getAction("/neorelay?device=${dni}&command={\"FROST_ON\":\"${deviceid}\"}")
- return cmds
- }
- def childFrostOff(String dni) {
- //Send Child Frost On command
- def cmds = []
- def deviceid = dni.replaceAll("neostat", "").replaceAll("-", " ")
- log.debug "Requesting frost off for child ${deviceid}"
- cmds << getAction("/neorelay?device=${dni}&command={\"FROST_OFF\":\"${deviceid}\"}")
- return cmds
- }
- def childSetFrost(int temp, String dni) {
- //Send Child Set Frost command
- def cmds = []
- def deviceid = dni.replaceAll("neostat", "").replaceAll("-", " ")
- log.debug "Requesting set frost at ${temp} degrees for child ${deviceid}"
- cmds << getAction("/neorelay?device=${dni}&command={\"SET_FROST\":[\"${temp}\", \"${deviceid}\"]}")
- return cmds
- }
- def parse(description) {
- def map = [:]
- def events = []
- def cmds = []
- //log.debug description
- if (description == "updated") return
- def descMap = parseDescriptionAsMap(description)
- def body = new String(descMap["body"].decodeBase64())
- def slurper = new JsonSlurper()
- def result = slurper.parseText(body)
- //log.debug result
- cmds << sendEvent(name: "lastcommand", value: "${result}", isStateChange: true)
- if (result.containsKey("relaydevice")) {
- //Received a device key, hence process the command (null devices will be ignored to make it easier to avoid bugs)
- if (result.relaydevice == "hubzonesetup") {
- //Device is a fake device for setting up zones, so create new devices if they dont exist
- for (def currentthermostat in result.relayresult) {
- //Iterate through each of the items in the result to create a device
- for ( item in currentthermostat) {
- def thisthermostatname = ""
- if (prestatname != null) {thisthermostatname = thisthermostatname + prestatname + " "}
- thisthermostatname = thisthermostatname + item.key
- if (poststatname != null) {thisthermostatname = thisthermostatname + " " + poststatname}
- log.debug "Adding child Name: ${thisthermostatname}, ID: ${item.value} to ${device.hub.id}"
- addChildDevice("cjcharles0", "Neo Thermostat", "neostat${item.key.replaceAll(" ", "-")}", device.hub.id, [name: thisthermostatname])
- }
- }
- }
- if (result.relaydevice == "hubzonerefresh") {
- //Device is a fake device for refreshing all zone info, so process responses out to each thermostat device
- log.debug "Received a refresh command from NeoHub"
- for (deviceinfo in result.relayresult.devices) {
- //If we have a devices key then it is an INFO command so process the events to update the DH
- if (deviceinfo.DEVICE_TYPE < 10) {
- //Device type < 10 should exclude repeaters
- def curdevicename = deviceinfo.device.replaceAll(" ", "-")
- log.debug curdevicename
- def curdevice = getChildDevices().find { it.deviceNetworkId == "neostat"+curdevicename}
- curdevice?.processNeoResponse(deviceinfo)
- }
- }
- }
- if (result.relaydevice.contains("neostat")) {
- //We got a command/response for an individual thermostat so send data to thermostat
- def resultdevice = getChildDevices().find { it.deviceNetworkId == result.relaydevice}
- resultdevice?.processNeoResponse(result)
- }
- }
- return cmds
- }
- private getAction(uri){
- log.debug "uri ${uri}"
- updateDNI()
- def userpass
- if(password != null && password != "")
- userpass = encodeCredentials("admin", password)
- def headers = getHeader(userpass)
- def hubAction = new physicalgraph.device.HubAction(
- method: "GET",
- path: uri,
- headers: headers
- )
- return hubAction
- }
- def parseDescriptionAsMap(description) {
- description.split(",").inject([:]) { map, param ->
- def nameAndValue = param.split(":")
- map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
- }
- }
- private getHeader(userpass = null){
- def headers = [:]
- headers.put("Host", getHostAddress())
- headers.put("Content-Type", "application/x-www-form-urlencoded")
- if (userpass != null)
- headers.put("Authorization", userpass)
- return headers
- }
- private encodeCredentials(username, password){
- def userpassascii = "${username}:${password}"
- def userpass = "Basic " + userpassascii.encodeAsBase64().toString()
- return userpass
- }
- private updateDNI() {
- if (state.dni != null && state.dni != "" && device.deviceNetworkId != state.dni) {
- device.deviceNetworkId = state.dni
- }
- }
- private getHostAddress() {
- if(getDeviceDataByName("bridgeip") && getDeviceDataByName("port")){
- return "${getDeviceDataByName("bridgeip")}:${getDeviceDataByName("bridgeport")}"
- }
- else {
- return "${bridgeip}:80"
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement