Integrate Somfy in Hubitat

Now I get another error message

Did you delete the method from 665 and then save the changes? Because I still see the method in your logs.

1

yes, see photo, but the line above is another one !?:grinning:

Okay....the numbering changes once you remove the lines above. I was referring to the old numbering as in the link that is supplied above. You need to put the URI lines back in. As i said, the lines you have to remove are the METHOD lines.

Try this code for the app.

/**
 *  Copyright (c) 2016-2018 Tibor Jakab-Barthi
 *
 *  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.
 *
 */

 /**
  * TODO:
  * Store TaHoma commands in map and reference map from Device Types so that Device Types can be generic.
  */
definition(
		name: "TaHoma® by Somfy",
		namespace: "jbt",
		author: "Tibor Jakab-Barthi",
		description: "Connect your TaHoma® system to SmartThings.",
		category: "My Apps",
		iconUrl: "http://tahomabysomfyapi.azurewebsites.net/img/TaHomaBySomfy.square150.png",
		iconX2Url: "http://tahomabysomfyapi.azurewebsites.net/img/TaHomaBySomfy.square300.png",
		singleInstance: true
)

preferences {
	page(name: "loginPage", title: "Log in with your TaHoma® credentials", nextPage: "settingsPage", uninstall: true) {
		section  {
			input(name: "username", type: "text", title: "Username", required: true, displayDuringSetup: true)
			input(name: "password", type: "password", title: "Password", required: true, displayDuringSetup: true)
		}

		section("General") {
			input(name: "debugMode", type: "bool", title: "Enable debug logging", defaultValue: false, displayDuringSetup: true)
		}
	}

	page(name: "settingsPage")
}

def settingsPage() {
	debug("settingsPage()")

	setDefaultValues()

	updateDevices()

	def interiorRollerBlindNames = getInteriorRollerBlindNames()
	def lightSensorNames = getLightIOSystemSensorNames()
	def rollerShutterNames = getRollerShutterNames()
	def rollerShutterWithLowSpeedManagementIOComponentNames = getRollerShutterWithLowSpeedManagementIOComponentNames()

	debug("rollerShutterWithLowSpeedManagementIOComponentNames $rollerShutterWithLowSpeedManagementIOComponentNames")

	dynamicPage(name: "settingsPage", title: "", install: true, uninstall: true) {
		section ("TaHoma® devices to control", hideWhenEmpty: true) {
			input(name: "selectedInteriorRollerBlindNames", type: "enum", title: "Interior Roller Blinds", description: "Tap to choose", required: false, multiple: true, metadata: [values: interiorRollerBlindNames], displayDuringSetup: true)
			input(name: "selectedLightIOSystemSensorNames", type: "enum", title: "Light Sensors", description: "Tap to choose", required: false, multiple: true, metadata: [values: lightSensorNames], displayDuringSetup: true)
			input(name: "selectedRollerShutterNames", type: "enum", title: "Roller Shutters RTS", description: "Tap to choose", required: false, multiple: true, metadata: [values: rollerShutterNames], displayDuringSetup: true)
			input(name: "selectedRollerShutterWithLowSpeedManagementIOComponentNames", type: "enum", title: "Roller Shutters IO", description: "Tap to choose", required: false, multiple: true, metadata: [values: rollerShutterWithLowSpeedManagementIOComponentNames], displayDuringSetup: true)
			input(name: "selectedSwitchNames", type: "enum", title: "Switches", description: "Tap to choose", required: false, multiple: true, metadata: [values: switchNames], displayDuringSetup: true)
		}
	}
}

// Cloud-Connected Device properties
def getCloudApiEndpoint() {
	"https://www.tahomalink.com/enduser-mobile-web/enduserAPI/" 
}

def getSmartAppVersion() {
	"1.3.20180612" 
}

// Device specific methods
def getDeviceId(device) { 
	return device.deviceURL;
}

def getDeviceName(device) { 
	return device.label;
}

def installed() {
	debug("installed(): ${settings}")

	atomicState.installedAt = now()

	updateDevices()

	initialize()
}

def uninstalled() {
	debug("uninstalled()")

	if (getChildDevices()) {
		removeChildDevices(getChildDevices())
	}
}

def updated() {
	debug("updated(): ${settings}")

	unsubscribe()

	updateDevices()

	initialize()
}

def debug(message) {
	if (settings.debugMode) {
		log.debug("SA $smartAppVersion: $message")
	}
}

def setDefaultValues() {
	debug("setDefaultValues()")

	def minute = 60 * 1000 // seconds * milliseconds

	atomicState.authorizationFailed = false
	atomicState.authorizationHeaderValue = ""
	atomicState.authorizationRetries = 1
	atomicState.authorizationRetriesRemaining = atomicState.authorizationRetries
	atomicState.authorizationTimeoutInMilliseconds = 1 * minute
	atomicState.authorizedAt = 0

	debug("setDefaultValues: atomicState: $atomicState")
}

def initialize() {
	debug("initialize()")

	setDefaultValues();

	def selectedDeviceCount = processSelectedInteriorRollerBlinds()
	selectedDeviceCount += processSelectedLightIOSystemSensors()
	selectedDeviceCount += processSelectedRollerShutters()
	selectedDeviceCount += processSelectedRollerShuttersWithLowSpeedManagementIOComponent()
	selectedDeviceCount += processSelectedSwitches()

	if (selectedDeviceCount == 0){
		log.error("No devices were selected.")
	}

	deleteUnselectedDevices()
}

def processSelectedInteriorRollerBlinds() {
	debug("processSelectedInteriorRollerBlinds()")

	if (!settings.selectedInteriorRollerBlindNames){
		settings.selectedInteriorRollerBlindNames = []
	}

	def selectedInteriorRollerBlinds = settings.selectedInteriorRollerBlindNames.each { dni ->
		def interiorRollerBlind = atomicState.interiorRollerBlinds[dni]

		if (!interiorRollerBlind) {
			debug("initialize: interiorRollerBlinds: ${atomicState.interiorRollerBlinds}")

			def errorMessage = "Interior Roller Blind '$dni' not found."
			log.error(errorMessage)

			throw new org.json.JSONException(errorMessage)
		}

		debug("interiorRollerBlind $interiorRollerBlind")

		def deviceName = getDeviceName(interiorRollerBlind)
		def deviceId = getDeviceId(interiorRollerBlind)

		def virtualDevice = getChildDevice(dni)

		if (virtualDevice) {
			debug("Found ${virtualDevice.name} with network id '$dni' already exists.")
		} else {
			def deviceTypeName = "TaHoma Roller Shutter RTS"

			debug("Creating new '$deviceTypeName' device '$deviceName' with id '$dni'.")

			virtualDevice = addChildDevice(app.namespace, deviceTypeName, dni, null, ["name": deviceId, "label": deviceName, "completedSetup": true])

			debug("virtualDevice ${virtualDevice}")

			debug("Created '$deviceName' with network id '$dni'.")
		}

		return virtualDevice
	}

	debug("User selected ${selectedInteriorRollerBlinds.size()} Interior Roller Blinds.")

	return selectedInteriorRollerBlinds.size()
}

def processSelectedLightIOSystemSensors() {
	debug("processSelectedLightIOSystemSensors()")

	if (!settings.selectedLightIOSystemSensorNames){
		settings.selectedLightIOSystemSensorNames = []
	}

	log.debug("selectedLightIOSystemSensorNames $selectedLightIOSystemSensorNames")
	def selectedLightIOSystemSensors = selectedLightIOSystemSensorNames.each { dni ->
		def lightIOSystemSensor = atomicState.lightIOSystemSensors[dni]

		if (!lightIOSystemSensor) {
			debug("initialize: lightIOSystemSensors: ${atomicState.lightIOSystemSensors}")

			def errorMessage = "Light IO System Sensor '$dni' not found."
			log.error(errorMessage)

			throw new org.json.JSONException(errorMessage)
		}

		debug("lightIOSystemSensor lightIOSystemSensor")

		def deviceName = getDeviceName(lightIOSystemSensor)
		def deviceId = getDeviceId(lightIOSystemSensor)

		def virtualDevice = getChildDevice(dni)

		if (virtualDevice) {
			debug("Found ${virtualDevice.name} with network id '$dni' already exists.")
		} else {
			def deviceTypeName = "TaHoma Light Sensor IO"

			debug("Creating new '$deviceTypeName' device '$deviceName' with id '$dni'.")

			def capabilities = [:]

			virtualDevice = addChildDevice(app.namespace, deviceTypeName, dni, null, ["name": deviceId, "label": deviceName, "completedSetup": true])
			virtualDevice.setCapabilities(capabilities)

			debug("virtualDevice ${virtualDevice}")

			debug("Created '$deviceName' with network id '$dni'.")
		}

		return virtualDevice
	}

	debug("User selected ${selectedLightIOSystemSensors.size()} TaHoma Light Sensor IO devices.")

	return selectedLightIOSystemSensors.size()
}

def processSelectedRollerShutters() {
	debug("processSelectedRollerShutters()")

	if (!settings.selectedRollerShutterNames){
		settings.selectedRollerShutterNames = []
	}

	def selectedRollerShutters = selectedRollerShutterNames.each { dni ->
		def rollerShutter = atomicState.rollerShutters[dni]

		if (!rollerShutter) {
			debug("initialize: rollerShutters: ${atomicState.rollerShutters}")

			def errorMessage = "Roller Shutter '$dni' not found."
			log.error(errorMessage)

			throw new org.json.JSONException(errorMessage)
		}

		debug("rollerShutter $rollerShutter")

		def deviceName = getDeviceName(rollerShutter)
		def deviceId = getDeviceId(rollerShutter)

		def virtualDevice = getChildDevice(dni)

		if (virtualDevice) {
			debug("Found ${virtualDevice.name} with network id '$dni' already exists.")
		} else {
			def deviceTypeName = "TaHoma Roller Shutter RTS"

			debug("Creating new '$deviceTypeName' device '$deviceName' with id '$dni'.")

			virtualDevice = addChildDevice(app.namespace, deviceTypeName, dni, null, ["name": deviceId, "label": deviceName, "completedSetup": true])

			debug("virtualDevice ${virtualDevice}")

			debug("Created '$deviceName' with network id '$dni'.")
		}

		return virtualDevice
	}

	debug("User selected ${selectedRollerShutters.size()} Roller Shutters.")

	return selectedRollerShutters.size()
}

def processSelectedRollerShuttersWithLowSpeedManagementIOComponent() {
	debug("processSelectedRollerShuttersWithLowSpeedManagementIOComponent()")

	if (!settings.selectedRollerShutterWithLowSpeedManagementIOComponentNames){
		settings.selectedRollerShutterWithLowSpeedManagementIOComponentNames = []
	}

	log.debug("selectedRollerShutterWithLowSpeedManagementIOComponentNames $selectedRollerShutterWithLowSpeedManagementIOComponentNames")
	def selectedRollerShuttersWithLowSpeedManagementIOComponent = selectedRollerShutterWithLowSpeedManagementIOComponentNames.each { dni ->
		def rollerShutterWithLowSpeedManagementIOComponent = atomicState.rollerShuttersWithLowSpeedManagementIOComponent[dni]

		if (!rollerShutterWithLowSpeedManagementIOComponent) {
			debug("initialize: rollerShuttersWithLowSpeedManagementIOComponent: ${atomicState.rollerShuttersWithLowSpeedManagementIOComponent}")

			def errorMessage = "Roller Shutter With Low Speed Management IO Component '$dni' not found."
			log.error(errorMessage)

			throw new org.json.JSONException(errorMessage)
		}

		debug("rollerShutterWithLowSpeedManagementIOComponent $rollerShutterWithLowSpeedManagementIOComponent")

		def deviceName = getDeviceName(rollerShutterWithLowSpeedManagementIOComponent)
		def deviceId = getDeviceId(rollerShutterWithLowSpeedManagementIOComponent)

		def virtualDevice = getChildDevice(dni)

		if (virtualDevice) {
			debug("Found ${virtualDevice.name} with network id '$dni' already exists.")
		} else {
			def deviceTypeName = "TaHoma Roller Shutter IO"

			debug("Creating new '$deviceTypeName' device '$deviceName' with id '$dni'.")

			def supportsDiscrete = rollerShutterWithLowSpeedManagementIOComponent.controllableName == 'io:RollerShutterWithLowSpeedManagementIOComponent'

			def capabilities = [supportsDiscrete: supportsDiscrete]

			virtualDevice = addChildDevice(app.namespace, deviceTypeName, dni, null, ["name": deviceId, "label": deviceName, "completedSetup": true])
			virtualDevice.setCapabilities(capabilities)

			debug("virtualDevice ${virtualDevice}")

			debug("Created '$deviceName' with network id '$dni'.")
		}

		return virtualDevice
	}

	debug("User selected ${selectedRollerShuttersWithLowSpeedManagementIOComponent.size()} Roller Shutters With Low Speed Management IO Component.")

	return selectedRollerShuttersWithLowSpeedManagementIOComponent.size()
}

def processSelectedSwitches() {
	debug("processSelectedSwitches()")

	if (!settings.selectedSwitchNames){
		settings.selectedSwitchNames = []
	}

	def selectedSwitches = selectedSwitchNames.each { dni ->
		def currentSwitch = atomicState.switches[dni]

		if (!currentSwitch) {
			debug("initialize: switches: ${atomicState.switches}")

			def errorMessage = "Switch '$dni' not found."
			log.error(errorMessage)

			throw new org.json.JSONException(errorMessage)
		}

		debug("switch $currentSwitch")

		def deviceName = getDeviceName(currentSwitch)
		def deviceId = getDeviceId(currentSwitch)

		def virtualDevice = getChildDevice(dni)

		if (virtualDevice) {
			debug("Found ${virtualDevice.name} with network id '$dni' already exists.")
		} else {
			def deviceTypeName = "TaHoma Switch"

			debug("Creating new '$deviceTypeName' device '$deviceName' with id '$dni'.")

			virtualDevice = addChildDevice(app.namespace, deviceTypeName, dni, null, ["name": deviceId, "label": deviceName, "completedSetup": true])

			debug("virtualDevice ${virtualDevice}")

			debug("Created '$deviceName' with network id '$dni'.")
		}

		return virtualDevice
	}

	debug("User selected ${selectedSwitches.size()} switches.")

	return selectedSwitches.size()
}

def deleteUnselectedDevices() {
	debug("deleteUnselectedDevices()")

	def delete

	if ((settings.selectedInteriorRollerBlindNames && settings.selectedInteriorRollerBlindNames.size() > 0) 
		|| (settings.selectedLightIOSystemSensorNames && settings.selectedLightIOSystemSensorNames.size() > 0) 
		|| (settings.selectedRollerShutterNames && settings.selectedRollerShutterNames.size() > 0) 
		|| (settings.selectedRollerShutterWithLowSpeedManagementIOComponentNames && settings.selectedRollerShutterWithLowSpeedManagementIOComponentNames.size() > 0) 
		|| (settings.selectedSwitchNames && settings.selectedSwitchNames.size() > 0)) {
		debug("Delete devices not selected by user.")

		delete = getChildDevices().findAll { 
			!settings.selectedInteriorRollerBlindNames.contains(it.deviceNetworkId) &&
			!settings.selectedLightIOSystemSensorNames.contains(it.deviceNetworkId) &&
            !settings.selectedRollerShutterNames.contains(it.deviceNetworkId) &&
            !settings.selectedRollerShutterWithLowSpeedManagementIOComponentNames.contains(it.deviceNetworkId) &&
            !settings.selectedSwitchNames.contains(it.deviceNetworkId)
		}
	} else {
		delete = getAllChildDevices()
	}

	log.warn("Delete: ${delete}, deleting ${delete.size()} devices.")

	delete.each { deleteChildDevice(it.deviceNetworkId) }
}

def getAuthorizationHeaderValue() {
	debug("getAuthorizationHeaderValue()")

	if (atomicState.authorizationHeaderValue == "" || atomicState.authorizedAt < now() - atomicState.authorizationTimeoutInMilliseconds) {
		debug("getAuthorizationHeaderValue: Authorizing with server.")

		atomicState.authorizationHeaderValue = getAuthorizationHeaderValueCore()
	} else {
		debug("getAuthorizationHeaderValue: Using cached token.")
	}

	return atomicState.authorizationHeaderValue
}

def getAuthorizationHeaderValueCore() {
	debug("getAuthorizationHeaderValueCore()")

	atomicState.authorizationFailed = false
	atomicState.authorizationHeaderValue = ""

	def requestParams = [
		uri: cloudApiEndpoint,
		path: 'login',
		headers: [
			'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
		]
	]

	debug("$requestParams")

	requestParams.body = [
		'userId':	settings.username,
		'userPassword':	settings.password
	]

	try {
		httpPost(requestParams) { resp ->
			if (resp.status == 200) {
				debug("getAuthorizationHeaderValueCore(): resp.data ${resp.data}")

				if (resp.data && resp.data.success == true) {
					def cookieHeader = resp.headers.'Set-Cookie'

					if (cookieHeader.contains('JSESSIONID')) {
						def cookieParts = cookieHeader.split(';')
						if (cookieParts.length > 0) {
							atomicState.authorizationHeaderValue = cookieParts[0]

							debug("getAuthorizationHeaderValueCore(): authorizationHeaderValue ${atomicState.authorizationHeaderValue}")

							atomicState.authorizationFailed = false
							atomicState.authorizationRetriesRemaining = atomicState.authorizationRetries
							atomicState.authorizedAt = now()
						}
					}
				}
			}
			else {
				log.error("getAuthorizationHeaderValueCore(): Failed: ${resp.status}")
			}
		}
	} catch (groovyx.net.http.HttpResponseException e) {
		log.error("getAuthorizationHeaderValueCore(): Error: ${e}")

		atomicState.authorizationHeaderValue = ""

		if (e.statusCode == 401) {
			if (atomicState.authorizationRetriesRemaining > 0) {
				debug("Retry authorization $atomicState.authorizationRetriesRemaining time(s).")

				atomicState.authorizationRetriesRemaining = atomicState.authorizationRetriesRemaining - 1

				atomicState.authorizationHeaderValue = getAuthorizationHeaderValueCore()
			} else {
				atomicState.authorizationFailed = true
			}
		}
	}

	return atomicState.authorizationHeaderValue
}

def removeChildDevices(childDevices) {
	debug("removeChildDevices($childDevices)")

    childDevices.each {
		try {
			deleteChildDevice(it.deviceNetworkId)
		} catch (Exception e) {
			debug("removeChildDevices ${it.deviceNetworkId} $e")
		}
    }
}

def getDeviceNames(devices) {
	debug("getDeviceNames($devices)")

	def names = [:]

	devices.each { dni, device ->
		names[dni] = getDeviceName(device)
	}

	debug("names $names")

	return names
}

def getInteriorRollerBlindNames() {
	debug("getInteriorRollerBlindNames()")

	def interiorRollerBlindNames = [:]

	atomicState.interiorRollerBlinds.each { dni, interiorRollerBlind ->
		interiorRollerBlindNames[dni] = getDeviceName(interiorRollerBlind)
	}

	debug("interiorRollerBlindNames $interiorRollerBlindNames")

	return interiorRollerBlindNames
}

def getLightIOSystemSensorNames() {
	debug("getLightIOSystemSensorNames()")

	def names = getDeviceNames(atomicState.lightIOSystemSensors)

	debug("names $names")

	return names
}

def getRollerShutterNames() {
	debug("getRollerShutterNames()")

	def rollerShutterNames = [:]

	atomicState.rollerShutters.each { dni, rollerShutter ->
		rollerShutterNames[dni] = getDeviceName(rollerShutter)
	}

	debug("rollerShutterNames $rollerShutterNames")

	return rollerShutterNames
}

def getRollerShutterWithLowSpeedManagementIOComponentNames() {
	debug("getRollerWithLowSpeedManagementIOComponentShutterNames()")

	def rollerShutterWithLowSpeedManagementIOComponentNames = [:]

	atomicState.rollerShuttersWithLowSpeedManagementIOComponent.each { dni, rollerShutterWithLowSpeedManagementIOComponent ->
		rollerShutterWithLowSpeedManagementIOComponentNames[dni] = getDeviceName(rollerShutterWithLowSpeedManagementIOComponent)
	}

	debug("rollerShutterWithLowSpeedManagementIOComponentNames $rollerShutterWithLowSpeedManagementIOComponentNames")

	return rollerShutterWithLowSpeedManagementIOComponentNames
}

def getSwitchNames() {
	debug("getSwitchNames()")

	def switchNames = [:]

	atomicState.switches.each { dni, currentSwitch ->
		switchNames[dni] = getDeviceName(currentSwitch)
	}

	debug("switchNames $switchNames")

	return switchNames
}

def poll() {
	debug("poll()")

	updateDevices()

	updateChildDevices()
}

def refresh() {
	debug("refresh()")

	poll()
}

def updateChildDevices() {
	debug("updateChildDevices()")

	try {
		def childDevices = getChildDevices()

		debug("updateChildDevices childDevices: ${childDevices}")

		childDevices.each { childDevice ->
			try {
				def eventData = [:]

				def deviceData = atomicState.rawDeviceData[childDevice.deviceNetworkId]
                
                log.debug("deviceData.states ${deviceData.states}")

				if (deviceData && deviceData.states) {
					deviceData.states.each { state ->
                    	//log.debug("state $state")
						if (state.name == "core:ClosureState") {
							eventData["level"] = state.value
						} else if (state.name == "core:LuminanceState") {
							eventData["illuminance"] = state.value
						}
					}
				}

				log.debug("Event data ${eventData}")

				childDevice.generateEvents(eventData)
			} catch (Exception e) {
				log.error("Exception updating device ${childDevice.name}: ${e}")
			}
		}
	} catch (Exception e) {
        log.error("Exception updating devices: ${e}")
    }
}

def updateDevices() {
	debug("updateDevices()")

	def requestParams = [
		uri: cloudApiEndpoint,
		path: 'setup',
		headers: [
			'Cookie': getAuthorizationHeaderValue()
		]
	]

	debug("$requestParams")

	try {
		httpGet(requestParams) { resp ->
			debug("updateDevices(): resp.data ${resp.data}")

			if (resp.status == 200 && resp.data) {
				def lightIOSystemSensors = [:]
				def rawDeviceData = [:]
				def rollerShutters = [:]
				def rollerShuttersWithLowSpeedManagementIOComponent = [:]
				def interiorRollerBlinds = [:]
				def switches = [:]

				//def slurper = new groovy.json.JsonSlurper()
				//def result = slurper.parseText('{"devices": [{"creationTime": 1524144461000,      "lastUpdateTime": 1524144461000,      "label": "Kidsroom east",      "deviceURL": "rts://1201-2886-4711/16776321",      "shortcut": false,      "controllableName": "io:RollerShutterWithLowSpeedManagementIOComponent",      "states": [        {          "name": "core:NameState",          "type": 3,          "value": "Kidsroom east"        },        {          "name": "core:PriorityLockTimerState",          "type": 1,          "value": 0        },        {          "name": "core:StatusState",          "type": 3,          "value": "available"        },        {          "name": "core:RSSILevelState",          "type": 2,          "value": 80.0        },        {          "name": "core:ClosureState",          "type": 1,          "value": 66        },        {          "name": "core:OpenClosedState",          "type": 3,          "value": "open"        }      ],      "attributes": [],      "available": true,      "enabled": true,      "placeOID": "45bf640c-b9fb-4703-8ec6-4d88e49abd2d",      "widget": "PositionableRollerShutterWithLowSpeedManagement",      "type": 1,      "oid": "56f526d7-cffc-4460-91a8-3bb53b6ed0ca",      "uiClass": "RollerShutter" }]}')
				//def result = slurper.parseText('{"devices": [{"creationTime": 1524144461000,      "lastUpdateTime": 1524144461000,      "label": "IO test blind",      "deviceURL": "rts://1201-2886-4711/16776321",      "shortcut": false,      "controllableName": "io:RollerShutterGenericIOComponent",      "states": [        {          "name": "core:NameState",          "type": 3,          "value": "IO test blind"        },        {          "name": "core:PriorityLockTimerState",          "type": 1,          "value": 0        },        {          "name": "core:StatusState",          "type": 3,          "value": "available"        },        {          "name": "core:RSSILevelState",          "type": 2,          "value": 80.0        },        {          "name": "core:ClosureState",          "type": 1,          "value": 66        },        {          "name": "core:OpenClosedState",          "type": 3,          "value": "open"        }      ],      "attributes": [],      "available": true,      "enabled": true,      "placeOID": "45bf640c-b9fb-4703-8ec6-4d88e49abd2d",      "widget": "PositionableRollerShutterWithLowSpeedManagement",      "type": 1,      "oid": "56f526d7-cffc-4460-91a8-3bb53b6ed0ca",      "uiClass": "RollerShutter" }]}')
				//def result = slurper.parseText('{"devices": [{"creationTime": 1524144461000,      "lastUpdateTime": 1524144461000,      "label": "IO test light sensor",      "deviceURL": "io://1201-2886-666/777",      "shortcut": false,      "controllableName": "io:LightIOSystemSensor",      "states": [{ "name": "core:LuminanceState", "type": 2, "value": 90000.0 }      ],      "attributes": [],      "available": true,      "enabled": true,      "placeOID": "45bf640c-b9fb-4703-8ec6-4d88e49abd2d",      "widget": "PositionableRollerShutterWithLowSpeedManagement",      "type": 1,      "oid": "56f526d7-cffc-4460-91a8-3bb53b6ed0ca",      "uiClass": "RollerShutter" }]}')
				//resp.data.devices = result.devices
				if (resp.data.devices) {
					resp.data.devices.each { device ->
                        //debug("-----------xxxxxxxxxxx---------- ${device}")

						def dni = [app.id, getDeviceId(device)].join('.')

						if (device.controllableName == 'rts:BlindRTSComponent') {
							interiorRollerBlinds[dni] = device
							rawDeviceData[dni] = device
						} else if (device.controllableName == 'rts:RollerShutterRTSComponent') {
							rollerShutters[dni] = device
							rawDeviceData[dni] = device
						} else if (device.controllableName == 'rts:OnOffRTSComponent') {
							switches[dni] = device
							rawDeviceData[dni] = device
						} else if (device.controllableName == 'io:LightIOSystemSensor') {
							lightIOSystemSensors[dni] = device
							rawDeviceData[dni] = device
						} else if (device.controllableName == 'io:RollerShutterWithLowSpeedManagementIOComponent') {
							rollerShuttersWithLowSpeedManagementIOComponent[dni] = device
							rawDeviceData[dni] = device
						} else if (device.controllableName == 'io:RollerShutterGenericIOComponent') {
							rollerShuttersWithLowSpeedManagementIOComponent[dni] = device
							rawDeviceData[dni] = device
						}
					}
				}

				debug("updateDevices(): interiorRollerBlinds ${interiorRollerBlinds}")
				debug("updateDevices(): lightIOSystemSensors ${lightIOSystemSensors}")
				debug("updateDevices(): rawDeviceData ${rawDeviceData}")
				debug("updateDevices(): rollerShutters ${rollerShutters}")
				debug("updateDevices(): rollerShuttersWithLowSpeedManagementIOComponent ${rollerShuttersWithLowSpeedManagementIOComponent}")
				debug("updateDevices(): switches ${switches}")

				atomicState.interiorRollerBlinds = interiorRollerBlinds
				atomicState.lightIOSystemSensors = lightIOSystemSensors
                atomicState.rawDeviceData = rawDeviceData
				atomicState.rollerShutters = rollerShutters
				atomicState.rollerShuttersWithLowSpeedManagementIOComponent = rollerShuttersWithLowSpeedManagementIOComponent
				atomicState.switches = switches
				atomicState.devicesUpdatedAt = now()
			}
			else {
				log.error("updateDevices(): Failed: ${resp.status}")
			}
		}
	} catch (groovyx.net.http.HttpResponseException e) {
		log.error("updateDevices(): Error: ${e}")

		if (e.statusCode == 401) {
			atomicState.authorizationFailed = true
		}
	}
}

def executeCommand(commandId, rollerShutterId, label, parameters = "") {
	debug("executeCommand($commandId, $rollerShutterId, $label, $parameters)")

	label = "$label ($rollerShutterId; SmartThings $smartAppVersion)";

	def body = "{\"label\":\"$label\",\"actions\":[{\"deviceURL\":\"$rollerShutterId\",\"commands\":[{\"name\":\"$commandId\",\"parameters\":[$parameters]}]}]}"

	def requestParams = [
		uri: cloudApiEndpoint,
		path: 'exec/apply',
		headers: [
			'Cookie': getAuthorizationHeaderValue()
		],
		body: body
	]

	debug("requestParams: $requestParams")

	def executionId

	try {
		httpPostJson(requestParams) { resp ->
			if (resp.status == 200 && resp.data) {
				debug("executeCommand(): resp.data ${resp.data}")

				refresh()

				executionId = resp.data.execId
			}
			else {
				log.error("executeCommand(): Failed: ${resp.status}")
			}
		}
	} catch (groovyx.net.http.HttpResponseException e) {
		log.error("executeCommand(): Error: ${e}")

		if (e.statusCode == 401) {
			atomicState.authorizationFailed = true
		}
	}

	debug("executeCommand: $commandId done: executionId: $executionId")

	return executionId
}

def stopExecution(executionId, label) {
	debug("stopExecution($executionId, $label)")

	def requestParams = [
		uri: cloudApiEndpoint,
		path: "exec/current/setup/$executionId",
		headers: [
			'Cookie': getAuthorizationHeaderValue()
		],
	]

	debug("$requestParams")

	def result

	try {
		httpDelete(requestParams) { resp ->
			result = resp.status
		}
	} catch (groovyx.net.http.HttpResponseException e) {
		log.error("stopExecution(): Error: ${e}")

		result = e

		if (e.statusCode == 401) {
			atomicState.authorizationFailed = true
		}
	}

	return result
}

def close(rollerShutterId, label) {
	debug("close($rollerShutterId, $label)")

	def executionId = executeCommand("close", rollerShutterId, "Close $label")

	return executionId
}

def identify(rollerShutterId, label) {
	debug("identify($rollerShutterId, $label)")

	def executionId = executeCommand("identify", rollerShutterId, "Identify $label")

	return executionId
}

def open(rollerShutterId, label) {
	debug("open($rollerShutterId, $label)")

	def executionId = executeCommand("open", rollerShutterId, "Open $label")

	return executionId
}

def presetPosition(rollerShutterId, label) {
	debug("presetPosition($rollerShutterId, $label)")

	def executionId = executeCommand("my", rollerShutterId, "My position $label")

	return executionId
}

def stop(executionId, label) {
	debug("stop($executionId, $label)")

	stopExecution(executionId, "Stop $label")
}

def switchOff(switchId, label) {
	debug("switchOff($switchId, $label)")

	def executionId = executeCommand("off", switchId, "$label off")

	return executionId
}

def switchOn(switchId, label) {
	debug("switchOn($switchId, $label)")

	def executionId = executeCommand("on", switchId, "$label on")

	return executionId
}
1 Like

Thank you very much, now the app works !!
I am logged in but I still cannot see my sun tents!

That I can't help you with. I would recommend going over to the ST forum and posting on the original thread where the app came from. It's possible that it just doesn't work anymore because of changes in the API. Did you look at the main page for the repo in github?

There's also a driver that you have to install.

FYI...i did a quick look and for some reason the device driver is using parent settings but the device doesn't have a parent child relationship defined. So, I dunno how this thing works.

yes, I know, I am trying to install this 'TaHomaRollerShutterRTS.DeviceHandler.groovy' but I get another error. unexpected token: * @ line 8, column 2.

I'm new here and I don't understand all that well.:innocent::grinning:

sorry, I mean this: TaHomaSwitch.DeviceHandler.groovy and give this error: No signature of method: Script1.icon () is applicable for argument types: (java.util.LinkedHashMap) values: [[title: Update Icon]] Possible solutions: on (), run (), run (), main (java.lang.String), main (java.util.List), main ([Ljava.lang.String;)

Sorry...but you're basically asking for someone to develop an integration for this device at this point. And I don't really have any interest in this device. That said, TaHoma does have IFTTT integration. Have you looked at integrating them that way instead of with this driver/app which you can't use?

1 Like

SmartApp still works on SmartThings. On Hubitat, the SmartApp doesn't render the devices. The devices ARE being discovered in the logs. But they are not populating the radio button display.

Wondering how easy it would be to refactor that part of the SmartApp to something Hubitat friendly. Happy to read some primer to get me going.

1 Like

This is an old thread that covered some basics re: porting from ST to HE:

I hope that in the near future somebody gets this app to work on hubitat.

Hi, I searched the community for Somfy threads and this one has some recent activity. I recently switched over to Hubitat from SmartThings and has been using GitHub - bendews/smartthings-somfy-mylink: SmartThings Device Handler for Somfy MyLink with my SmartThings to have it talk via LAN to a Somfy MyLink wifi device. The MyLink device sends the RTS codes to the Somfy shades, see Somfy's myLink: Home automation for all your window coverings.

The SmartThings code needed some modifications to work on Hubitat and I've made them in the "hubitat" branch of my own fork here: GitHub - scelfo/smartthings-somfy-mylink at hubitat.

I sent the original author a pull request but he isn't using SmartThings anymore so doesn't want to maintain a branch and suggested I fork and take over. Anyone on this thread have a Somfy MyLink and want to help test my fork of the project? My fork would be Hubitat specific so I'd cut it down even further from its current state (i.e. remove SmartThings app icons) and write a Hubitat specific set of setup instructions.

1 Like

@scelfo I am using the same code from Smartthings and would like to test out your code.

Douglas, it looks like I am taking this over, but it will be a few weeks - I’m getting over some medical issues. @scelfo has decided to go with the Bond controller, and there are some issues with his employer owning code he writes, complicated by the licenses that the original programmer used. I’ll shoot you a note when I am well enough to take it up.

Is there any update on the Somfy Mylink integration and licensing/development as you mentioned in your last post? Please advise and thanks again for stepping up to support

It’s coming. I’m recovering from chemotherapy, that knocked me back a bit.

Shoot!! didn't know. Health and family first. Look forward to when you can. Thanks for the update

For others interested, I picked up where @scelfo left off. I've added support for hubitat package manager and bottom-up shades. I changed a few other little things in the logic and capabilities. I've tested it with my setup at home.

1 Like

thanks for the updated enhancements in the driver. One question I cannot find to simplify this is where do you start to populate the Mylink hubs that are in place now and align them as IP targets in HE so you can interact with those shades/zones they control. I have gone through all of the literature and for the life of me cannot find this given at a minimum the 2 drivers are loaded on my C7 now. thanks