I have a garage on my property with bi-fold carriage house doors. I made a door opener/closer that uses linear actuators controlled by an Arduino Mega.
I want to add a WiFi interface (via ESP8266) to allow the controller to send door status to HE, and receive commands from HE.
I think Websockets is the appropriate technology for this. I know I could use MQTT or the Maker API REST interface, or some Zigbee/ZWave contact sensors and a Shelly 1 relay, but I think Websockets is the appropriate technology for my situation.
I know how to implement a websockets server on the ESP8266, but Iām struggling with the Websockets interface to HE.
I read the HE Documentation Websocket Interface page, and I know I need to implement parse and webSocketStatus methods in a driver.
Is there an example Websockets HE driver I can look at to help me get started? Is there other documentation I should be looking at?
I can give an example from one of my drivers (an update to my SamsungTvRemote is is over 1000 lines and has a lot of different ws commands. I have simplified below:
/* ===== HUBITAT INTEGRATION VERSION =====================================================
====*/
def driverVer() { return "3.1.2" }
import groovy.json.JsonOutput
metadata {
definition (name: "Websocket Example",
namespace: "davegut",
author: "David Gutheinz",
importUrl: ""
){
capability "Switch"
}
preferences {
input ("deviceIp", "text", title: "device Ip", defaultValue: "")
}
}
// ===== Installation, setup and update =====
def installed() {
}
def updated() {
}
def on() {
// This is where you define the message to actually send.
sendMessage("on")
}
def off() {
sendMessage("off")
}
def sendCommand(command) {
// Check if socket is open. If not, connect
if (device.currentValue("wsStatus") != "open") {
connect(funct)
pauseExecution(300)
}
// Wait then sent the command
interfaces.webSocket.sendMessage(command)
// I usually close. This will reschedule if another message is
// sent prior to the 30 seconds.
runIn(30, close)
}
def connect() {
// Below are examples of the path and parameters for a command. This will be SPECIFIC
// to you device. Format is ip:port plus the path defined. It may also contain other
// data (in the below: NAME and TOKEN)
// example for a not secure interface (http)
def url = "ws://${deviceIp}:8001/api/v2/channels/samsung.remote.control?name=test"
interfaces.webSocket.connect(url)
// for a secure interface (https)
def url = "wss://${deviceIp}:8002/api/v2/channels/samsung.remote.control?name=${name}&token=tokenHere"
interfaces.webSocket.connect(url, ignoreSSLIssues: true)
}
def close() {
logDebug("close")
interfaces.webSocket.close()
}
def webSocketStatus(message) {
// A good behaving sokey will send a response. From that you
// will parse the status as open, closed, etc.
def status
if (message == "status: open") {
status = "open"
} else if (message == "status: closing") {
status = "closed"
} else if (message.substring(0,7) == "failure") {
status = "closed-failure"
// if a failure is detected, close the interface
close()
}
sendEvent(name: "wsStatus", value: status)
}
def parse(resp) {
// Will be specific to your device. Here, the response is parsed json
// and from that I can get the event then switch for various state updates.
// I use try to isolate any error.
def logData = [:]
try {
resp = parseJson(resp)
def event = resp.event
logData << [EVENT: event]
switch(event) {
case "ms.channel.connect":
def newToken = resp.data.token
if (newToken != null && newToken != state.token) {
state.token = newToken
logData << [TOKEN: "updated"]
} else {
logData << [TOKEN: "noChange"]
}
break
case "ms.error":
logData << [STATUS: "Error, Closing WS",DATA: resp.data]
close()
break
case "ms.channel.ready":
case "ms.channel.clientConnect":
case "ms.channel.clientDisconnect":
break
default:
logData << [STATUS: "Not Parsed", DATA: resp.data]
break
}
logDebug("parse: ${logData}")
} catch (e) {
logData << [STATUS: "unhandled", ERROR: e]
logWarn("parse: ${logData}")
}
}