@steve.hoge thanks I'm new to Hubitat and Groovy (like yesterday new ) but gave this a try based on your Python code (I love Python). This Driver so far will get the access token after you enter in your UAID and Secret Key, save, then press configure. This will also then populate the devicesList state variable after you refresh. Then you can plugin the deviceToken and deviceID in the preferences and save, and now use the refresh button to pull those state variables from the sensor. Note I'm using this with a motion sensor, so be sure to change the part to your device type if not using MotionSenor in the getMotionSensorDetails command and also the updateState logic to reflect your state variables.
I don't quite know how to setup polling or use the HTTP Callback API for YoLink I see mentioned on the API docs so that the state would update based on a motion event. Sorry if it is a little rough, still learning everything but wanted to share in case it helps anyone else get closer to something working.
/*
* YoLink API
*
* Talks to the YoLink API using user credentials from mobile app
* Based off Python code by @steve.hoge and using snippets of various project examples including: https://github.com/hubitat/HubitatPublic/tree/master/examples/drivers
*
*/
metadata {
definition(name: "YoLink API", namespace: "community", author: "Dev Dre4ms") {
capability "Configuration"
command "refresh"
attribute "access_token", "text"
attribute "deviceList", "text"
attribute "alertInterval", "text"
attribute "battery", "text"
attribute "devTemperature", "text"
attribute "ledAlarm", "text"
attribute "nomotionDelay", "text"
attribute "sensitivity", "text"
attribute "state", "text"
attribute "lastMotion", "text"
}
}
preferences
{
section
{
input "uaid", "text", title: "YoLink UAID", required: true
input "secret", "password", title: "YoLink Secret Key", required: true
input "deviceID", "text", title: "Device ID", required: false
input "deviceToken", "text", title: "Device Token", required: false
input name: "logEnable", type: "bool", title: "Enable debug logging", defaultValue: false
}
}
def refresh() {
def motionState = getMotionSensorDetails(state.access_token, deviceToken, deviceID)
updateState(motionState)
logDebug("Motion state status:${motionState}")
}
def updateState(Map motionState)
{
state.alertInterval = motionState.data.state.alertInterval
state.battery = motionState.data.state.battery
state.devTemperature = motionState.data.state.devTemperature
state.ledAlarm = motionState.data.state.ledAlarm
state.nomotionDelay = motionState.data.state.nomotionDelay
state.sensitivity = motionState.data.state.sensitivity
state.state = motionState.data.state.state
state.lastMotion = motionState.data.reportAt
}
def logDebug(msg)
{
if (logEnable)
{
log.debug(msg)
}
}
def configure()
{
getAccessToken()
//Get devicelist and update attribute to see deviceToken/deviceId
def command_response = post_command(state.access_token, "Home.getDeviceList", [:])
logDebug("Devices List: ${command_response}")
state.devicesList = command_response
}
def getAccessToken()
{
def postParams = genParamsPre()
postParams['body'] = ["grant_type": "client_credentials"]
try
{
token_response = httpPostExec(postParams, false)
logDebug("Received access token: ${token_response.access_token}")
state.access_token = token_response.access_token
return token_response.access_token
}
catch (Exception e)
{
logDebug("Error retrieving access token from YoLinkAPI")
}
}
def getTokenURI()
{
return "https://api.yosmart.com/open/yolink/token"
}
def getAPIURI()
{
return "https://api.yosmart.com/open/yolink/v2/api"
}
def genParamsPre()
{
def params =
[
uri: getTokenURI(),
headers:
[
'Authorization': "Basic " + ("${uaid}:${secret}").bytes.encodeBase64().toString()
],
contentType: 'application/json'
]
return params
}
def genCommandParams(String token)
{
def params =
[
uri: getAPIURI(),
headers:
[
'Authorization': "Bearer " + token
],
contentType: 'application/json'
]
return params
}
def httpPostExec(params, throwToCaller = false)
{
logDebug("httpPostExec(${params})")
def response = [:]
try
{
httpPost(params) { resp ->
if (resp.success)
{
response = resp.getData()
logDebug("Success: ${response}")
}
}
}
catch (Exception e)
{
logDebug("httpPostExec() failed: ${e.message}")
if(throwToCaller)
{
throw(e)
}
}
return response
}
def getCurrentTime() {
now = new Date()
return now.getTime()
}
def post_command(String token, String method, Map methodData) {
def params = genCommandParams(token)
def commandData = methodData
commandData['method'] = method
commandData['time'] = getCurrentTime().toString()
params["body"] = commandData
return httpPostExec(params, true)
}
def getMotionSensorDetails(String token, String deviceToken, String deviceID)
{
//This needs to be updated for the type of sensor you'd like to get the state from, replace MotionSensor.getState with your device type
def deviceData = post_command(token, 'MotionSensor.getState', [
'token': deviceToken,
'targetDevice': deviceID,
'params': [:]])
}
def logsOff() {
log.warn "debug logging disabled..."
device.updateSetting("logEnable", [value: "false", type: "bool"])
}