{"id":31490,"date":"2024-08-15T21:35:13","date_gmt":"2024-08-16T04:35:13","guid":{"rendered":"https:\/\/www.podfeet.com\/blog\/?p=31490"},"modified":"2024-08-15T22:16:23","modified_gmt":"2024-08-16T05:16:23","slug":"philips-hue-programming-part-1-of-3","status":"publish","type":"post","link":"https:\/\/www.podfeet.com\/blog\/2024\/08\/philips-hue-programming-part-1-of-3\/","title":{"rendered":"Philips Hue Programming (Part 1 of 3)"},"content":{"rendered":"<p>A few years ago, I decided I needed to get some smart light bulbs. I need to be able to set very dim light in my study for the nights I am on call for my job. After trying some cheap no-name bulbs, I discovered the Nanoleaf Essentials range. These were affordable and also came with HomeKit compatibility.<\/p>\n<p>Recently I had one fail and it was the last straw, at least for use in my study. It was, if I recall correctly, the fourth such failure in a few years.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignright size-medium wp-image-31491\" src=\"https:\/\/www.podfeet.com\/blog\/wp-content\/uploads\/2024\/07\/PhilipsHueStarterKit-White_Colour-E27Screw_1445x-300x224.jpg\" alt=\"A product image of three Philips Hue bulbs and a Hue Bridge. The bulbs are lined up on an angle receding from the viewer and to the left, towards the bridge in the background. The bulbs are mostly white, lit up in a purple colour. The bridge is white with a lit up blue ring.\" width=\"300\" height=\"224\" srcset=\"https:\/\/www.podfeet.com\/blog\/wp-content\/uploads\/2024\/07\/PhilipsHueStarterKit-White_Colour-E27Screw_1445x-300x224.jpg 300w, https:\/\/www.podfeet.com\/blog\/wp-content\/uploads\/2024\/07\/PhilipsHueStarterKit-White_Colour-E27Screw_1445x-768x573.jpg 768w, https:\/\/www.podfeet.com\/blog\/wp-content\/uploads\/2024\/07\/PhilipsHueStarterKit-White_Colour-E27Screw_1445x-650x485.jpg 650w, https:\/\/www.podfeet.com\/blog\/wp-content\/uploads\/2024\/07\/PhilipsHueStarterKit-White_Colour-E27Screw_1445x.jpg 881w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/>I put out the call in the Podfeet slack and in a couple of other places for a reliable brand of bulbs. There was an overwhelming majority in favour of the Philips Hue bulbs. I had originally complained these were expensive and I didn\u2019t like the idea of needing a hub. The Nanoleaf bulbs do not need one.<\/p>\n<p>Allison explained the hub actually improved the reliability and speed of operation so I tentatively moved that aspect into the plus column. But they are still expensive, especially given the inclusion of a hub. Events conspired to get me over that hurdle, too, as I managed to score a starter kit at well less than half price.<\/p>\n<p>In my study I have four bulb sockets \u2014 three spotlights which got the starter pack bulbs, plus a dome light near the door. Because of the tiny, dark room, I also had a couple of Nanoleaf light strips \u2014 one along the back of my desk as a backlight, and one at the top of the wall behind my chair, as a fill light. As I got to know the features of the Hue app, I began to crave that ALL of the lights in my room would be controllable by it.<\/p>\n<p>I\u2019ve now bought an additional bulb for the doorway, and have just replaced the backlight strip with a Hue \u201cWhite and colour ambience\u201d light strip. While playing around with the <em>very cool<\/em> music sync feature \u2014 seriously, I have an Apple Music playlist called \u201c<a href=\"https:\/\/music.apple.com\/nz\/playlist\/light-show\/pl.u-d2MXjFM55B2m\">Light Show<\/a>\u201d now \u2014 I got to wondering what bespoke automations I might be able to create with Hue lights.<\/p>\n<p>Back in January of 2023, I contributed a <a href=\"https:\/\/www.podfeet.com\/blog\/2023\/01\/stream-deck-down-the-rabbit-hole-part-1\/\">three<\/a> <a href=\"https:\/\/www.podfeet.com\/blog\/2023\/01\/stream-deck-down-the-rabbit-hole-part-2\">part<\/a> <a href=\"https:\/\/www.podfeet.com\/blog\/2023\/01\/stream-deck-down-the-rabbit-hole-part-3\/\">series<\/a> to the podcast, called \u201cStream Deck \u2014 Down the Rabbit Hole\u201d. In that, I mentioned I had looked for ways to directly control my Nanoleaf lights from automations. I had settled on an app called <a href=\"https:\/\/apps.apple.com\/nz\/app\/homecontrol-menu-for-homekit\/id1547121417?mt=12\">HomeControl<\/a> which provides an interface to HomeKit via a URL scheme. This has worked OK for me, but does seem to fall foul of HomeKit reliability problems. I wondered whether Philips Hue gave me any new opportunities.<\/p>\n<p>Oh, boy, howdy, does it what!!<\/p>\n<p>It took me a little digging around to find out what was needed to start controlling my Hue lights but, I am happy to report anyone can do it without needing to sign up to anything. It does help to create a free developer account with Philips, but that is just about getting access to detailed information. With just what I will talk about, you can control your lights to suit most automation needs.<\/p>\n<p>Everything I cover will be done from a terminal. I\u2019ve been using the standard macOS terminal with zsh but anywhere you can access the curl command and be on the same network as your Hue Bridge, you should be OK.<\/p>\n<p>Before we move on, that <em>is<\/em> one pre-requisite. While Hue bulbs can work without a Bridge, the Hue API is an API to the Bridge.<\/p>\n<p>The first thing we need to do is find out what IP address the Bridge is on. One way to do this is from the Hue app for iPhone or Android. In the settings, tap My Hue System, then the info button for the Hue Bridge you wish to control. The IP address will be listed in the top section.<\/p>\n<p>Alternatively, you may be able to look up the address from your router\u2019s GUI. If you go this way, you might like to reserve an IP address for the bridge so you can always use the same address for your automations.<\/p>\n<p>Every action we do will be running a <code>curl<\/code> command to talk to the bridge. We will either ask for information, or provide information, or sometimes both. The first command we need is to set up a user account on the Bridge.<\/p>\n<p>Knowing your bridge IP address, let\u2019s enter the first command, which will set up a user profile to use going forward.<\/p>\n<p><code>curl --request POST --data '{\"devicetype\":\"app_name#instance_name\", \"generateclientkey\":true}' https:\/\/192.168.1.15\/api<\/code><\/p>\n<p>You\u2019ll get an error back which tells you the extra step you missed.<\/p>\n<p><code>[{\"error\":{\"type\":101,\"address\":\"\",\"description\":\"link button not pressed\"}}]<\/code><\/p>\n<p>Press the button on your Bridge, then run the command again and you\u2019ll get a more useful response.<\/p>\n<p><code>[{\"success\":{\"username\":\"Qn74cB7YlKursSzMYyPL4pr5oLWxayBqhKyjFD10\",\"clientkey\":\"8B249DD79EF93F004595E2AC2DFEC942\"}}]<\/code><\/p>\n<p>Record both the user name and client key in your password manager. For what I will cover, you\u2019ll only use the username.<\/p>\n<p>Now let\u2019s list out all the devices your bridge knows about.<\/p>\n<p><code>curl --request GET --header \"hue-application-key: <span style=\"color: #ff0000;\">Qn74cB7YlKursSzMYyPL4pr5oLWxayBqhKyjFD10<\/span>\" https:\/\/<span style=\"color: #ff0000;\">192.168.1.15<\/span>\/clip\/v2\/resource\/device<\/code><\/p>\n<p>But hang on, <code>curl<\/code> returns an error.<\/p>\n<p><code>curl: (60) SSL certificate problem: unable to get local issuer certificate<\/code><\/p>\n<p>If we were writing an app that many people would use with their own Bridges, we\u2019d need to deal with validating the certificate. Because we\u2019re just playing with our own Bridge, we need to tell <code>curl<\/code> not to worry about that, by adding an extra flag to the command: <code>-k<\/code><\/p>\n<p><code>curl -k --request GET --header \"hue-application-key: <span style=\"color: #ff0000;\">Qn74cB7YlKursSzMYyPL4pr5oLWxayBqhKyjFD10<\/span>\" https:\/\/<span style=\"color: #ff0000;\">192.168.1.15<\/span>\/clip\/v2\/resource\/device<\/code><\/p>\n<p>Now we get a huge glop of data back. It\u2019s JSON, so if you have <code>jq<\/code> installed, you can format it. To learn about <code>jq<\/code>, check out <a href=\"https:\/\/pbs.bartificer.net\/pbs155\">Programming by Stealth episode 155<\/a> onwards.<\/p>\n<p><code>curl -k --request GET --header \"hue-application-key: <span style=\"color: #ff0000;\">Qn74cB7YlKursSzMYyPL4pr5oLWxayBqhKyjFD10<\/span>\" https:\/\/<span style=\"color: #ff0000;\">192.168.1.15<\/span>\/clip\/v2\/resource\/device | jq<\/code><\/p>\n<p>The formatted JSON takes many more lines but you can probably make sense of it now. It contains an error array, hopefully empty, and a data array. Here\u2019s one example entry from my data array.<\/p>\n<pre><code class=\"language-json\">     {\n      \"id\": \"194ab81c-46d8-1e4a-7c66-751137cdc984\",\n      \"id_v1\": \"\/lights\/4\",\n      \"product_data\": {\n        \"model_id\": \"LCA006\",\n        \"manufacturer_name\": \"Signify Netherlands B.V.\",\n        \"product_name\": \"Hue color lamp\",\n        \"product_archetype\": \"sultan_bulb\",\n        \"certified\": true,\n        \"software_version\": \"1.116.3\",\n        \"hardware_platform_type\": \"100b-114\"\n      },\n      \"metadata\": {\n        \"name\": \"Study A1\",\n        \"archetype\": \"ceiling_round\"\n      },\n      \"identify\": {},\n      \"services\": [\n        {\n          \"rid\": \"a4edc74c-5ac1-4d82-bbc1-3066fda691fb\",\n          \"rtype\": \"zigbee_connectivity\"\n        },\n        {\n          \"rid\": \"f355d81f-7b92-4113-90ad-f92626fc5dd9\",\n          \"rtype\": \"light\"\n        },\n        {\n          \"rid\": \"4c019efe-0915-4d34-bc4b-d2fa3b8270fc\",\n          \"rtype\": \"entertainment\"\n        },\n        {\n          \"rid\": \"6e9993c3-0684-4bff-9c62-323ddd8164e3\",\n          \"rtype\": \"taurus_7455\"\n        },\n        {\n          \"rid\": \"f1f8214a-68ff-4295-ad79-b801d10132bf\",\n          \"rtype\": \"device_software_update\"\n        }\n      ],\n      \"type\": \"device\"\n    },\n<\/code><\/pre>\n<p>There are several interesting things to see here.<\/p>\n<p>The <code>id<\/code> key specifies the overall id of the device, though we can get more specific.<\/p>\n<p>The <code>product_data<\/code> object is comprised of lots of information about what the device actually <em>is<\/em>, along with its software version.<\/p>\n<p>The <code>metadata<\/code> object contains the name you have given the device in the Hue app, as well as the <code>archetype<\/code>. In this case, I have described my light as being a round ceiling light.<\/p>\n<p>Lastly, the <code>services<\/code> object gives us information about each of the roles the device can play. It\u2019s one of the <code>rid<\/code> keys in here that we\u2019re interested in. The one that relates to an <code>rtype<\/code> of <code>light<\/code>. We\u2019re going to use that to check on and control the light, so note it down.<\/p>\n<p>Next, let\u2019s get some information about the light service for this device. Once again, we will pass the output to <code>jq<\/code> for formatting.<\/p>\n<p><code>curl -k --request GET --header \"hue-application-key: <span style=\"color: #ff0000;\">Qn74cB7YlKursSzMYyPL4pr5oLWxayBqhKyjFD10<\/span>\" https:\/\/<span style=\"color: #ff0000;\">192.168.1.15<\/span>\/clip\/v2\/resource\/light\/<span style=\"color: #ff0000;\">f355d81f-7b92-4113-90ad-f92626fc5dd9<\/span> | jq<\/code><\/p>\n<p>At the top, we get back some of the same information we already had, but then it gets interesting.<\/p>\n<pre><code class=\"language-json\">      \"on\": {\n        \"on\": true\n      },\n      \"dimming\": {\n        \"brightness\": 100.0,\n        \"min_dim_level\": 0.20000000298023225\n      },\n      \"dimming_delta\": {},\n      \"color_temperature\": {\n        \"mirek\": 156,\n        \"mirek_valid\": true,\n        \"mirek_schema\": {\n          \"mirek_minimum\": 153,\n          \"mirek_maximum\": 500\n        }\n      },\n      \"color_temperature_delta\": {},\n      \"color\": {\n        \"xy\": {\n          \"x\": 0.3143,\n          \"y\": 0.3301\n        },\n        \"gamut\": {\n          \"red\": {\n            \"x\": 0.6915,\n            \"y\": 0.3083\n          },\n          \"green\": {\n            \"x\": 0.17,\n            \"y\": 0.7\n          },\n          \"blue\": {\n            \"x\": 0.1532,\n            \"y\": 0.0475\n          }\n        },\n        \"gamut_type\": \"C\"\n      },\n<\/code><\/pre>\n<p>There is plenty more after the section I have shown, which mostly relates to advanced functions, but here we have the basics of this colour-capable bulb.<\/p>\n<p>The <code>on<\/code> object details whether the bulb is currently on or not.<\/p>\n<p>The <code>dimming<\/code> object shows the current dimming level.<\/p>\n<p>The <code>color_temperature<\/code> object shows the current white temperature. More on this in a bit.<\/p>\n<p>The <code>color<\/code> object seems to contain a lot of information to define a colour! More on this later, too.<\/p>\n<p>Let\u2019s see how we can turn the light on or off. From here on in, we\u2019ll use a fairly standard <code>curl<\/code> command with differences in just one of the values.<\/p>\n<p><code>curl -k --request PUT --header \"hue-application-key: <span style=\"color: #ff0000;\">Qn74cB7YlKursSzMYyPL4pr5oLWxayBqhKyjFD10<\/span>\" --data '{\"on\":{\"on\":false}}' https:\/\/<span style=\"color: #ff0000;\">192.168.1.15<\/span>\/clip\/v2\/resource\/light\/<span style=\"color: #ff0000;\">f355d81f-7b92-4113-90ad-f92626fc5dd9<\/span><\/code><\/p>\n<p>This is very similar to the previous command we used with two important differences. The request type is now <code>PUT<\/code>, and we are supplying some <code>--data<\/code>.<\/p>\n<p>Note that the <code>--data<\/code> value is single quoted to allow for the double quotes in the value. That value is a snippet of JSON which should look quite familiar.<\/p>\n<p>When we queried the light\u2019s current state, it returned its power state, amongst other data, as <code>{\"on\":{\"on\":false}}<\/code> and that is exactly the form of value we supplied to change it.<\/p>\n<p>After running the command, you will get a small snippet of JSON in response. It contains the id of the service we targeted and, once again, an errors array which is hopefully empty. And, of course, the light should have acted on your instruction.<\/p>\n<p><code>{\"data\":[{\"rid\":\"f366d87e-78d2-4f13-93fd-f2862d5c5879\",\"rtype\":\"light\"}],\"errors\":[]}<\/code><\/p>\n<p>You can probably imagine that we can set some of the other values the same way, and you\u2019d be right. Let\u2019s try colour temperature.<\/p>\n<p>From here on in, I\u2019m just going to show the <code>--data<\/code> values, as the rest of the command is always the same, at least for this light.<\/p>\n<p><code>--data '{\"color_temperature\":{\"mirek\":500}}'<\/code><\/p>\n<p>Wait\u2026 what\u2019s a mirek? More commonly called \u201cmired\u201d, it\u2019s short for <em>reciprocal megakelvin<\/em>. The mirek value is based on a colour temperature scale you\u2019re possibly more familiar with \u2014 degrees Kelvin. Let\u2019s say you want to set the colour temperature to 6500\u00baK. To calculate the equivalent mirek value, you divide a million degrees Kelvin by the number of degrees Kelvin you want. So 1,000,000 divided by 6,500 is about 153.85.<\/p>\n<p>If you were paying attention earlier, you may have seen the number 153. When we queried the light service, as well as the <em>current<\/em> mirek value, we were also given <code>mirek_minimum<\/code> and <code>mirek_maximum<\/code> values \u2014 153 and 500, respectively. If we divide 1,000,000 by 500, we of course get 2,000. So the light has a temperature range of 2,000 \u2013 6,500 degrees Kelvin.<\/p>\n<p>With my previous command, I set my bulb to a very warm colour temperature \u2014 basically orange. I can set it back to its brightest white by changing the <code>mirek<\/code> value to 153.<\/p>\n<p>The next thing we can try is setting multiple attributes at once. Let\u2019s set the colour temperature and the brightness.<\/p>\n<p><code>--data '{\"color_temperature\":{\"mirek\":312},\"dimming\":{\"brightness\":50.0}}' <\/code><\/p>\n<p>Brightness is an easy one \u2014 it\u2019s just a number from 0.1 to 100.0 from dimmest to brightest. Specifying multiple attributes is as simple as putting one after another, separated by a comma.<\/p>\n<p>What about setting a colour, for colour-capable bulbs? It\u2019s easily executed, though figuring out what numbers you need for a specific colour can be a challenge.<\/p>\n<p>You might be used to specifying colour with three components \u2014 red, green, and blue, or \u201cRGB\u201d. It\u2019s not going to be that easy for your Hue lights. Instead we supply only <em>two<\/em> numbers, which are X and Y in a CIE colour space. Basically, they are coordinates on a chromaticity diagram.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignright\" src=\"https:\/\/developers.meethue.com\/wp-content\/uploads\/2018\/02\/color.png\" width=\"352\" height=\"400\" \/><\/p>\n<p>If, like me, you can think in an RGB colour space, then there <em>is<\/em> a way to convert between that and the CIE colour space, but it\u2019s not straightforward at all. Instead, I recommend a resource like <a href=\"https:\/\/www.dumbswitches.com\/philips-hue-lights-popular-xy-color-values\/\">this page from \u201cDumb Switches\u201d<\/a> I found, which gives you values for a whole bunch of colours. There is also a link to a Python library that can do the calculations if you\u2019re keen.<\/p>\n<p>Anyway, here are the data values to pass for each of red, green, and blue.<\/p>\n<p><code>--data '{\"color\":{\"xy\":{\"x\":0.675,\"y\":0.322}}}'<\/code><\/p>\n<p><code>--data '{\"color\":{\"xy\":{\"x\":0.4091,\"y\":0.518}}}'<\/code><\/p>\n<p><code>--data '{\"color\":{\"xy\":{\"x\":0.167,\"y\":0.04}}}'<\/code><\/p>\n<p>There are many, many more things you can do using the Hue API, like grouping lights, reading sensors, streaming \u201centertainment\u201d data to lights, and more, but I\u2019ll leave it here for now. If you wish to explore more, sign up for a free developer account at <a href=\"https:\/\/developers.meethue.com\" rel=\"noopener\" target=\"_blank\">developers.meethue.com<\/a>.<\/p>\n<p>In a future segment, I\u2019ll tell you how I worked around needing to look up those giant light IDs with a little bit of command line magic.<\/p>\n<p>But just before I go, here\u2019s a <code>--data<\/code> value to try that\u2019s pretty nifty.<\/p>\n<p><code>--data '{\"effects\":{\"effect\":\"prism\"}}'<\/code><\/p>\n","protected":false},"excerpt":{"rendered":"<p>A few years ago, I decided I needed to get some smart light bulbs. I need to be able to set very dim light in my study for the nights I am on call for my job. After trying some cheap no-name bulbs, I discovered the Nanoleaf Essentials range. These were affordable and also came [&hellip;]<\/p>\n","protected":false},"author":29,"featured_media":31491,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[147],"tags":[1356,1136,176,229],"class_list":["post-31490","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-posts","tag-controlled-lighting","tag-home-automation","tag-programming","tag-terminal"],"jetpack_featured_media_url":"https:\/\/www.podfeet.com\/blog\/wp-content\/uploads\/2024\/07\/PhilipsHueStarterKit-White_Colour-E27Screw_1445x.jpg","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.podfeet.com\/blog\/wp-json\/wp\/v2\/posts\/31490","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.podfeet.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.podfeet.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.podfeet.com\/blog\/wp-json\/wp\/v2\/users\/29"}],"replies":[{"embeddable":true,"href":"https:\/\/www.podfeet.com\/blog\/wp-json\/wp\/v2\/comments?post=31490"}],"version-history":[{"count":4,"href":"https:\/\/www.podfeet.com\/blog\/wp-json\/wp\/v2\/posts\/31490\/revisions"}],"predecessor-version":[{"id":31729,"href":"https:\/\/www.podfeet.com\/blog\/wp-json\/wp\/v2\/posts\/31490\/revisions\/31729"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.podfeet.com\/blog\/wp-json\/wp\/v2\/media\/31491"}],"wp:attachment":[{"href":"https:\/\/www.podfeet.com\/blog\/wp-json\/wp\/v2\/media?parent=31490"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.podfeet.com\/blog\/wp-json\/wp\/v2\/categories?post=31490"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.podfeet.com\/blog\/wp-json\/wp\/v2\/tags?post=31490"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}