You are right I can't find it now either. I did save it, however.
Here is the version that I got to compile. I have the original somewhere I need to find it though. When I try to install, it does find my Leviosa zone controller. The log it produces list the IP of the zone controller.
It looks like at that point it tries to ask for connected shades but it never gets a response. I have yet to ask Leviosa if there is any documented API available. Haven't really took the time to look into it any further. Been really busy at work lately and that is when I tend to look into stuff like this, during my less busy times at work.
/**
* Leviosa Shades Smart App
*
*/
definition(
name: "Leviosa WiShadeController Service Manager",
namespace: "atlascoder",
author: "Leviosashades",
description: "A Controller that can manage motorized shade from mobile App in Home or via Internet",
category: "My apps",
iconUrl: "https://s3.us-east-2.amazonaws.com/leviosa-pub/Icon-48.png",
iconX2Url: "https://s3.us-east-2.amazonaws.com/leviosa-pub/Icon-88.png",
iconX3Url: "https://s3.us-east-2.amazonaws.com/leviosa-pub/Icon-172.png"
)
preferences {
page name: "searchTargetSelection", title: "Shade Groups Setup", nextPage: "deviceDiscovery"
section("You are starting to connect your Leviosa Motor Shades managed through wiSHadeControllers. Your wiShadesController(s) must be setup correctly before to start to discover and connect them."){}
section("Your wiShadesController(s) must be setup correctly before to start to discover and connect them."){}
page name: "deviceDiscovery", title: "Shade Groups Discovery", content: "deviceDiscovery"
}
def deviceDiscovery() {
state.searchTarget = "urn:schemas-upnp-org:service:TwoWayMotor:1"
log.debug "Discovery start for ${state.searchTarget}"
def options = [:]
def devices = getVerifiedDevices()
devices.each {
def key = it.value.ssdpUSN.split(':')[1]
def value = it.value.name ?: "Group ${key}"
options["${key}"] = value
}
ssdpSubscribe()
ssdpDiscover()
verifyDevices()
return dynamicPage(name: "deviceDiscovery", title: "Discovery Started!", nextPage: "", refreshInterval: 5, install: true, uninstall: true) {
section("Please wait while we discover your shade groups. Discovery can take five minutes or more, so sit back and relax! Select your really connected group from list below once discovered.") {
input "selectedDevices", "enum", required: false, title: "Select Groups (${options.size() ?: 0} found)", multiple: true, options: options
}
}
}
def installed() {
log.debug "Installed with settings: ${settings}"
initialize()
}
def updated() {
log.debug "Updated with settings: ${settings}"
unsubscribe()
initialize()
}
def initialize() {
unsubscribe()
unschedule()
ssdpSubscribe()
log.debug "Selected devices: ${selectedDevices}"
if (selectedDevices) {
addDevices()
}
runEvery5Minutes("ssdpDiscover")
}
void ssdpDiscover() {
sendHubCommand(new hubitat.device.HubAction("lan discovery ${state.searchTarget}", hubitat.device.Protocol.LAN))
}
void ssdpSubscribe() {
subscribe(location, "ssdpTerm.${state.searchTarget}", ssdpHandler)
}
Map verifiedDevices() {
def devices = getVerifiedDevices()
def map = [:]
devices.each {
def key = it.value.ssdpUSN.split(':')[1]
def value = it.value.name ?: "Group ${key}"
map["${key}"] = value
}
map
}
void verifyDevices() {
def devices = getDevices().findAll { it?.value?.verified != true }
devices.each {
int port = convertHexToInt(it.value.deviceAddress)
String ip = convertHexToIP(it.value.networkAddress)
String host = "${ip}:${port}"
log.debug "Requesting http://${host}${it.value.ssdpPath}"
sendHubCommand(new hubitat.device.HubAction("GET ${it.value.ssdpPath} HTTP/1.1\r\nHOST: $host\r\n\r\n", hubitat.device.Protocol.LAN, host, [callback: deviceDescriptionHandler]))
}
}
def getVerifiedDevices() {
getDevices().findAll{ it.value.verified == true }
}
def getDevices() {
if (!state.devices) {
state.devices = [:]
}
state.devices
}
def addDevices() {
def devices = getDevices()
log.debug "Current devices: ${devices.toString()}"
log.debug "Selected devices: ${selectedDevices}"
def selDevs = []
if (selectedDevices instanceof String) {
selDevs << selectedDevices
}
else {
selDevs += selectedDevices
}
log.debug "Selected devices: ${selDevs}"
selDevs.each { dni ->
log.debug "dni = ${dni}"
def selectedDevice = devices.find { it.value.ssdpUSN.split(':')[1] == dni }
def d
if (selectedDevice) {
d = getChildDevices()?.find {
it.deviceNetworkId == selectedDevice.value.ssdpUSN.split(':')[1]
}
}
log.debug "selectedDevice => ${selectedDevice}"
if (!d) {
log.debug "Creating Window Blind Device with dni: ${dni}"
addChildDevice("atlascoder", "LeviosaController", dni, selectedDevice?.value.hub, [
"label": selectedDevice?.value?.name ?: "LeviosaController",
"data": [
"mac": selectedDevice.value.mac,
"ip": selectedDevice.value.networkAddress,
"port": selectedDevice.value.deviceAddress,
"dni": dni
]
])
}
}
}
def ssdpHandler(evt) {
def description = evt.description
def hub = evt?.hubId
def parsedEvent = parseLanMessage(description)
parsedEvent << ["hub":hub]
def devices = getDevices()
String ssdpUSN = parsedEvent.ssdpUSN.toString()
def uuid = ssdpUSN.split(':')[1]
log.debug "Response from uuid:${uuid}"
if (devices."${uuid}") {
def d = devices."${uuid}"
log.debug "Update uuid:${uuid} => ${d}"
if (d.networkAddress != parsedEvent.networkAddress || d.deviceAddress != parsedEvent.deviceAddress) {
d.networkAddress = parsedEvent.networkAddress
d.deviceAddress = parsedEvent.deviceAddress
def child = getChildDevice(uuid)
if (child) {
child.sync(parsedEvent.networkAddress, parsedEvent.deviceAddress)
}
}
} else {
log.debug "Add uuid:${uuid} => ${parsedEvent}"
devices << ["${uuid}" : parsedEvent]
}
}
void deviceDescriptionHandler(hubitat.device.HubResponse hubResponse) {
def body = hubResponse.xml
def devices = getDevices()
def device = devices.find { it?.key == body?.device?.UDN?.toString().split(':')[1] }
log.debug "Device by ${body?.device?.UDN?.toString().split(':')[1]} = > ${device}"
if (device) {
log.debug "Update device with name: ${body?.device?.friendlyName?.text()}"
device.value << [name: body?.device?.friendlyName?.text(), model: body?.device?.modelName?.text(), serialNumber: body?.device?.serialNum?.text(), verified: true]
}
}
private Integer convertHexToInt(hex) {
Integer.parseInt(hex,16)
}
private String convertHexToIP(hex) {
[convertHexToInt(hex[0..1]),convertHexToInt(hex[2..3]),convertHexToInt(hex[4..5]),convertHexToInt(hex[6..7])].join(".")
}