Ikea Blinds

This post up above is the EXACT instructions

If that doesn't work for you, please be specific on what you are having problems with. There are a lot of steps, so help others help you by narrowing down what the issue could be.

The driver definitely works, but you may need to reset/unpair the blinds from the gateway as with the pairing to Hubitat the gateway is totally out of play

1 Like

I will try - it's not quite as hard as it might seem. You'll just be copy/pasting some code into a text box in settings, and then selecting the driver from a drop down on the device page. I'll do a step by step at the bottom of this reply once I answer some other questions you have.

The remote and the blinds are both zigbee devices. Unfortunately the Ikea remote for the blinds has been a struggle to pair and get to work properly. BUT - once you have the blinds working with Hubitat, you can use ANY button remote that's supported by Hubitat! You can also use the Hubitat app dashboard, and you can control the blinds with Alexa/Google Home - both their app, and voice.

To get any button remote that works with Hubitat to control the blinds, you'll have to set up some basic rules in rule machine, but it's not too complex. The good news is that a lot of people in the forum would love to help you get a button remote (not the Ikea one, unfortunately) to control the blinds once you have the connected to Hubitat and working properly.

You will be able to easily replicate this automation using Hubitat rule machine. Again, it will look daunting at first, like gazing over the edge of the Grand Canyon. But then you'll realize that if you just take one-step-at-a-time and ask us for help on the forum, that it's really not that bad at all. :slight_smile: Again, everyone here wants to help you out! Well, almost everyone - I shouldn't use absolute terms. :smiley:

OK - with that out of the way, let's help you get the blinds set up with Hubitat. This will look like a lot of text, just because I went into every tiny detail. The whole process should take about 5 minutes.

Step 1: Pair the Tradfri repeater (USB outlet that came with the shades) to Hubitat in an outlet relatively close to the shade. To pair: Plug in the repeater into the USB plug and then into your outlet. The light will come on steady. To get it in pairing mode, with the repeater plugged in, use a safety-pin/sewing needle and insert it into the small hole next to the USB socket, you will feel the reset button and hold that down with the pin for 10-15 seconds. Remove the pin/needle and the white LED should start to blink. Then set your Hubitat to Zigbee discovery. There is a built-in driver in Hubitat for the Tradfri repeater, so once it is paired, this step is complete.

Step 2: Install this driver (click the link <---). See steps 2.1 - 2.5 for how to install the driver :slight_smile:

Step 2.1: Copy the text with all the code in the driver link above that @Ryan780 was kind of enough to modify so it is compatible with Hubitat.

Step 2.2: Open your Hub in your web browser, and in the navigation click on "<> Drivers Code"

Step 2.3: Click on "+ New Driver" in the top right corner of the Drivers Code page

Step 2.4: Place your mouse next to the the #1 right under where it says "New Driver" on the top-left of the screen. Then, paste the text you copied from the driver code above.

Step 2.5: Hit "Save" at the top of the page. Wait for the page to reload - this will indicate that the driver is saved.

(All you have done now is added the code for the driver to your Hub, but it wont do anything until the device, your Ikea Shades, are told to use this driver - we will get to that in a moment).

You can go back to the homepage of your hub interface now - you are done with code :slight_smile:

Step 3: Pair the blinds with Hubitat and tell it to use the driver from Step 2

  • Reset the blind
  • Press on both buttons for 5 seconds
  • An LED on the blind will begin to blink confirming they are reset
  • Open your Hubitat web interface
  • Click on Devices -> Discover Devices - > Zigbee
  • If the shades paired successfully, Hubitat will show that a Device was discovered.
  • NOW is where we tell the device (the shade) to use the driver from Step 2 above.
  • Click on the new device and it will take you to the device detail page.
  • At the bottom of the Device page, under "Device Information" is a dropdown that says "Type" click on that dropdown and scroll ALL THE WAY TO THE BOTTOM where the user created drivers are, and select "IKEA Window Blinds"
  • Click on "Save Device"
  • When the device page reloads, click on "Configure" this tells the Ikea shades to use the driver code from step 2.

Step 4: Test! On the Device page, click on the Close or Open buttons and make sure the shades are going up and down. If they respond to Close/Open on the device page, then everything worked!

Step 5: Set the maximum open/close for the shade. Get the shade to the exact height you want it to be when it is 100% closed. Then, on the shade itself, double-tab the down button next to the battery pack. The shade will move up and down a tiny bit indicating this was set properly. NOW when you tell the shade to close 100% this is as far as the shade will go.

OK, hopefully you made it all the way to step 5. If you did, now you can add the shades to a Hubitat dashboard. You can also add the shades to Alexa via Hubitat. NOTE - they may not behave exactly as you want in Alexa, but you can overcome that by again using Rule Machine. For me, I created a simple virtual switch in Alexa called "Shades". When I want them open, I say "Turn on shades" which turns on the virtual switch, and in turn triggers a basic rule to open the shades. Same with "Turn off shades" makes them close. You can certainly get a lot more complex then this, but this was enough to get my WAF through the roof!

If you have questions, report back here, and people will try to help you.

If you DO get them working this far, and want help setting up a rule, you can ask again in this thread, or start a new topic asking for specific Rule Machine help. Either way will get you the assistance you need. Good luck!

12 Likes

Thank you so much for the detailed instructions. I know that took a lot of time. I am grateful. I tried to cut and paste the code yesterday and I'm not sure what I did but I kept getting an error. Today it worked perfectly. I'll work on getting everything else paired up and working soon. Thanks again!

Ok I got everything else up and running now. It works with Alexa (although it thinks its a light and 0% is open and 100% is closed which seems backwards in my mind. But I tricked Alexa with a routine so the verbal commands to open and close the blinds seem more natural. Saying "turn on the blind" just seems stupid. Next step is to buy a remote I guess. Any suggestions?

That's fantastic news! Nicely done!

This thread might help you out: Best Remote for Ikea Blinds?

I saw this one mentioned in the Zigbee button controller recommendation thread that might work well. I haven't used it though so I can't give a review. https://www.amazon.com/AduroSmart-ERIA-Wireless-Dimming-Switch/dp/B07HJHJWGT

I used the driver in post 120 but found the position/level is the opposite of what Alexa and Google define for shades. I discovered it using the Community-maintained Google Home integration which allows the shades to be properly exposed to Google Home as a shade and not using dimmer switch hacks. Asking Google to open my shades resulted in closing and vice versa.

These are wanting 0 = closed and 100 = open (using a light bulb analogy, 0% = dark = shades closed, 100% = bright = shades open). Below is a modified version of the driver that applies 100 minus the position to do this inversion and allows it to work a little more intuitively depending on how your mind wraps around the idea.

/**
 *
 *
 *	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.
 *
 *  
 *  first release for IKEA smart window blinds for hubitat adapted from the driver for ST by Wayne Man
 *  
 *  3/31/20 Josh Sutinen 
 *  - Inverted level to match expectation of Google Assistant and Alexa where 0 = closed and 100 = open
 */
import hubitat.zigbee.zcl.DataType

metadata {
    definition(name: "IKEA Window Blinds", namespace: "ryan780", author: "ryan780", ocfDeviceType: "oic.d.blind", mnmn: "SmartThings", vid: "generic-shade") {
        capability "Actuator"
        capability "Configuration"
        capability "Refresh"
        capability "Window Shade"
        capability "Health Check"
        capability "Switch Level"
		capability "Battery"					

        command "pause"
        
       	attribute "lastCheckin", "String"
		attribute "lastOpened", "String"

		fingerprint inClusters: "0000,0001,0003,0004", manufacturer: "IKEA of Sweden", model: "FYRTUR block-out roller blind"
    }
}

private getCLUSTER_BATTERY_LEVEL() { 0x0001 }
private getCLUSTER_WINDOW_COVERING() { 0x0102 }
private getCOMMAND_OPEN() { 0x00 }
private getCOMMAND_CLOSE() { 0x01 }
private getCOMMAND_PAUSE() { 0x02 }
private getCOMMAND_GOTO_LIFT_PERCENTAGE() { 0x05 }
private getATTRIBUTE_POSITION_LIFT() { 0x0008 }
private getATTRIBUTE_CURRENT_LEVEL() { 0x0000 }
private getCOMMAND_MOVE_LEVEL_ONOFF() { 0x04 }

private List<Map> collectAttributes(Map descMap) {
	List<Map> descMaps = new ArrayList<Map>()

	descMaps.add(descMap)

	if (descMap.additionalAttrs) {
		descMaps.addAll(descMap.additionalAttrs)
	}

	return descMaps
}

// Parse incoming device messages to generate events
def parse(String description) {
    log.debug "description:- ${description}"
    def now = new Date().format("yyyy MMM dd EEE h:mm:ss a", location.timeZone)
    //  send event for heartbeat    
    sendEvent(name: "lastCheckin", value: now)
    if (description?.startsWith("read attr -")) {
        Map descMap = zigbee.parseDescriptionAsMap(description)
        if (supportsLiftPercentage() && descMap?.clusterInt == CLUSTER_WINDOW_COVERING && descMap.value) {
            log.debug "attr: ${descMap?.attrInt}, value: ${descMap?.value}, descValue: ${Integer.parseInt(descMap.value, 16)}, ${device.getDataValue("model")}"
            List<Map> descMaps = collectAttributes(descMap)
            def liftmap = descMaps.find { it.attrInt == ATTRIBUTE_POSITION_LIFT }
            if (liftmap && liftmap.value) {
                def newLevel = zigbee.convertHexToInt(liftmap.value)
                levelEventHandler(100-newLevel)
            }
        } else if (!supportsLiftPercentage() && descMap?.clusterInt == zigbee.LEVEL_CONTROL_CLUSTER && descMap.value) {
            def valueInt = Math.round((zigbee.convertHexToInt(descMap.value)) / 255 * 100)

            levelEventHandler(valueInt)
        }
		if (descMap?.clusterInt == CLUSTER_BATTERY_LEVEL && descMap.value) {
            log.debug "attr: ${descMap?.attrInt}, value: ${descMap?.value}, descValue: ${Integer.parseInt(descMap.value, 16)}"
            sendEvent(name: "battery", value: Integer.parseInt(descMap.value, 16))
        }
    }
}

def levelEventHandler(currentLevel) {
    def lastLevel = device.currentValue("level")
    log.debug "levelEventHandle - currentLevel: ${currentLevel} lastLevel: ${lastLevel}"
    if (lastLevel == "undefined" || currentLevel == lastLevel) { //Ignore invalid reports
        log.debug "Ignore invalid reports"
    } else {
        sendEvent(name: "level", value: currentLevel)
        if (currentLevel == 0 || currentLevel == 100) {
            sendEvent(name: "windowShade", value: currentLevel == 0 ? "closed" : "open")
        } else {
            if (lastLevel > currentLevel) {
																 
												  
                sendEvent([name:"windowShade", value: "closing"])
            } else if (lastLevel < currentLevel) {
                sendEvent([name:"windowShade", value: "opening"])
            }
            runIn(1, "updateFinalState", [overwrite:true])
        }
    }
												  
}

def updateFinalState() {
    def level = device.currentValue("level")
    log.debug "updateFinalState: ${level}"
    if (level > 0 && level < 100) {
        sendEvent(name: "windowShade", value: "partially open")
    }
}

def supportsLiftPercentage() {
    device.getDataValue("manufacturer") != "Feibit Co.Ltd"
}

def close() {
    log.info "close()"
    zigbee.command(CLUSTER_WINDOW_COVERING, COMMAND_CLOSE)

}

def open() {
    log.info "open()"
    zigbee.command(CLUSTER_WINDOW_COVERING, COMMAND_OPEN)
}

def setLevel(data, rate = null) {
						   
    log.info "setLevel()"
    def cmd
	data = data.toInteger()
    if (supportsLiftPercentage()) {
        cmd = zigbee.command(CLUSTER_WINDOW_COVERING, COMMAND_GOTO_LIFT_PERCENTAGE, zigbee.convertToHexString(100-data, 2))
    } else {
        cmd = zigbee.command(zigbee.LEVEL_CONTROL_CLUSTER, COMMAND_MOVE_LEVEL_ONOFF, zigbee.convertToHexString(Math.round(data * 255 / 100), 2))
    }

    return cmd
}

def pause() {
    log.info "pause()"
    zigbee.command(CLUSTER_WINDOW_COVERING, COMMAND_PAUSE)
}

/**
 * PING is used by Device-Watch in attempt to reach the Device
 * */

def ping() {
       return zigbee.readAttribute(CLUSTER_BATTERY_LEVEL, 0x0021) // Read the Battery Level
}

def refresh() {
    log.info "refresh()"
	
    def cmds
    if (supportsLiftPercentage()) {
        cmds = zigbee.readAttribute(CLUSTER_WINDOW_COVERING, ATTRIBUTE_POSITION_LIFT)
    } else {
        cmds = zigbee.readAttribute(zigbee.LEVEL_CONTROL_CLUSTER, ATTRIBUTE_CURRENT_LEVEL)
    }
    return cmds
}

def configure() {
    // Device-Watch allows 2 check-in misses from device + ping (plus 2 min lag time)
    log.info "configure()"
    sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
    log.debug "Configuring Reporting and Bindings."

    def cmds
    if (supportsLiftPercentage()) {
        cmds = zigbee.configureReporting(CLUSTER_WINDOW_COVERING, ATTRIBUTE_POSITION_LIFT, DataType.UINT8, 0, 600, null)
    } else {
        cmds = zigbee.levelConfig()
    }
    return refresh() + cmds
}

def setPosition(value){
	setLevel(value)
}
2 Likes

Add this line as its missing from the driver.

private getCOMMAND_CLOSE() { 0x01 }

Once done, then all works well for me :+1:

Just so it's clear for anyone coming into this conversation late:

The line Kev mentioned adding is indeed added to the code in post 180 by pastrd

(sorry, that wasn't clear when i was reading the past few posts and dug in and found that, so i thought i'd share that)

1st time I’ve ever seen these online orderable, so I was able to snag the model I needed,

1 Like

But the cost of delivery is more than the blind??? I was looking at the 30 inch width and to my area delivery was 199.00 which is more than the blind Cost? I'll pass.

thats odd. I just ordered 3 and a bunch of other stuff that was in my cart and the shipping was only 19.99.

Where do you live?!

Strange... it was just $5 for shipping for me

Screenshot 2020-04-08 12.10.44

I ordered a dozen blinds yesterday and also paid $19.99 for shipping.

1 Like

here you go? Just don't like us in West Virginia.

Oh man, sorry to see that!

I tried it here with that zipcode just to see if it was anything funky with your actual location or something like that... but nope, still showed the $199 price.

download

have you tried a few other local zip codes to see if it just happens to be a system glitch with yours or is it the entire area? I'd call them to see if you could order over the phone with realistic shipping costs.

Yes I try a few other Zip Codes and the shipment was the same 199.00?

You’re more than welcome to ship them my way and I’ll then ship to you, there’s no way that from me (outside Daytona Beach) to WV would cost anything near that

Try zip 32724 if interested

I am in Michigan, the shipping is a measley $129.
:-1:

Something is defiantly up with their system, there is no reason shipping should be all over the place like that. I just put in multiple different zipcodes with towns right next to each other and had either $99 or $49 for shipping, some of these are major cities too.

On a side note, anyone know if there will be different colors, seems like grey is it currently?