Leviosa motor shades

Following

That repo looks like it contains a mobile app not ST groovy code? If you can share your ported code maybe we can help but it’s really hard to troubleshoot when you can’t see the code.

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(".")
}

I sent a email to Leviosa today. So I will see if they respond.

ever get anywhere with this? I have levies shades and am looking to migrate from ST to habitat

I never heard anything from Leviosa. I thought I might as they asked me to join their beta program for the Zone firmware. I had, I thought, a pretty good back and forth with one of the developer's on some issues, but never heard back from them.

My Zone quit working and I had a Bond hub that I was using for a Fan my wife had bought for our bedroom and instead of buying another Zone I decided to try using the Bond hub to control the shades. I am using the HE Bond integration and it works really well with the shades.

I did make a slight change to the driver. The current drive only allowed you to open or close I added a raise and lower which moves the shade to the next setpoint.

Bummer, I’m really trying to get away from ST, I’ve had quite a few problems with it lately. I have bond fan controllers, but don’t use the their hub, they integrate with ST or Alexa through a skill. Thanks for info.

I actually used Echo speaks to integrate the shades with HE thru the Alexa skill for quite some time. That actually worked really well. If my Zone had not gone bad I probably would have never thought about using the Bond bridge.

When you say Echo, do you mean the Plus or Show models that has a hub built into it, or are you referring to the skills in Alexa? I have the leviosa Alexa skill and know that I can command the shades through Alexa. I also have the HE skill in Alexa, but haven’t done anything with it yet. Are you saying that I can manage leviosa shades in HE through those connections, as in built automation with other devices in HE?

I am. You of coarse need the Leviosa Zone. You create a virtual shade for each Leviosa shade and then when that virtual shade is activated it triggers a RM rule to control the actual Leviosa shade. You can use echo speaks. It will allow you to send a Alexa command to a any Alexa device just as if you speak to it directly. So the RM rule will send out the command "Alexa ask leviosa to open living room shade".

This will not work without internet as it is cloud based, but it worked really well for me. I basically do the same thing now except I am now using the Bond bridge to simulate the remote to send the command to the Leviosa shade as opposed to a Alexa command.

This is awesome, thank you! I'll mess with this in the next couple days.

Do you know if this same concept will work with Lutron Caseta lights & shades instead of having to get the pro bridge from lutron and talking over telnet?

Hi @terminal3, how did you go about adding the leviosa shades to the bond hub?

As I remember, I just went through the bond setup for a shade and let it learn the remote. It has worked really well. Have had much less trouble with it than I did with the Leviosa Zone. I made a slight modification to the bond shade driver, along with a open or close, which opens or closes the shade completely. My modification also allows you to use raise and lower, which raises or lowers to the next set point.

I see, I didn’t realize the bond replicates the RF signal, I was thinking it was some kind of direct connection to the shades. Thanks.

Well that is about as direct as you get with most pieces of wireless hardware, it has to be some kind of wireless signal whether Zigbee, Z-wave or Wifi.

The Bond hub integration is local, so that is another plus over the Zone method.

1 Like

Any progress with a native integration of Leviosa blinds? I have 5 that i used to use with ST

I have been happy with the Bond hub, it works really well with the Leviosa shades.

1 Like

Yeah hoping to not have to add another hub to mix. I removed ST, although there are a few things it can do HE can't yet but would love to not add another one.

Well you either have to have use the Leviosa Zone, or The Bond hub. So you have to add something.

1 Like

I have a Leviosa Zone but just no way to make it talk to Hubitat as far as I can tell. I can link it to Google or homekit but that wont get it into HE and I may just have to add ST back and connect to that and then go Hub to Hub but again hoping to limit the number of hubs.