When we last left the amalgamation of code, sensors, and things, we'd greatly improved the ability of the voice assistant system to set timers of arbitrary length and out effort into distinguishing them from each other. Since then, a hub attached to a component of the systems has regularly been failing to connect to and through the wifi, and there's a switch that has been having trouble with that as well. There's now a radio for the lights that has let them connect to local control instead of a failing hub. Many of the previous light controls have worked perfectly once the lights were renamed to their proper entity identifications. Some features have been lost for the moment, but there's a distinct possibility that they can be put back together with the use of the correct API calls. The switch, we'll have to see if it can be locally controlled or if we have to get a different type of switch and locally control that, instead. Or see whether the hub disappearing allows for greater and better control of that switch.
Right now, however, we get to enjoy a saga of doing things the wrong way repeatedly until something gets done correctly and it works. I have an old television that my ex had me buy for myself so that the older, heavier model didn't have to make a trip with me (or so that I wouldn't feel like I was only spending money on things for her, or both) that still works excellently for display reasons, except for one tiny thing: the Infrared (IR) sensor on it is busted. I have no idea when this happened, but that's the reality of it. With a working IR sensor, controlling this television from Home Assistant would be much easier, as there's already a trainable IR remote in the same room as the TV.
Assisting the cause is that this otherwise non-smart television has a Raspberry Pi single-board computer attached to it. (The Pi already provides a satellite instance of the voice assistant, so it's already part of the smart home infrastructure.) All of the Raspberry Pis have the ability, with the correct distribution packages, to use HDMI-CEC, a part of the HDMI specification that allows commands to be sent over an HDMI cable to compatible displays and systems to control those connected systems. It's most commonly used for things like turning on an audio system along with a TV or monitor, so that one power button gets the whole system up and running. The TV has a working HDMI-CEC bus on it, so the Pi can send commands over it to turn the TV on and off, change the volume, mute it, etc. It should be able to do basically anything that the CEC-O-MATIC says is part of the specification. Rather than have to send specific frames for common activities, there are some commands that cec-client can send as words instead. So, it's easy enough to scan the HDMI-CEC bus and figure out the addresses of the Pi and the TV, and to test that the bus works using specific syntax to format commands and pass them as arguments into cec-client. From the command line of the local machine, things work just fine. TV turns off and on again with those commands from the local console.
With local control established as working, at this point, there are options on how to turn that local control into remote access from the Home Assistant. Perhaps the most direct way would be to allow Home Assistant to access the Pi and run the shell command locally. This would require setting up a secure shell connection between the two machines. However, Home assistant is not equipped to transmit a username and password for authentication and instead has to use pregenerated keys copied to the correct locations on both machines to allow for the connection. It's a hassle, even though it's secure, and the first time I tried this, it never worked how I wanted it to, so I wasn't going to try that again.
A less direct method, but one that looked like it had promise, was to use a module (pyCEC) that could hook into Home Assistant's own HDMI-CEC integration by providing a bridge over the network so that Home assistant could see the remote CEC bus as if it were local and manipulated it in the same way. On a previous version of Home Assistant and the Pi, I managed to successfully set up the bridge and use it for remote control, although it requested compiling a library from source with correct bindings to work as a condition of sauces. I knew, however, that the relevant library had already been installed from the package manager on this iteration of the Pi, so it seemed wasteful to compile something when it was already there. The missing bindings, so that the library would work with Python 3, were contained in a different package available from the package manager, ask once installed, the remote bridge would work, or so I thought.
It did not, in fact, work like before, and I spent a significant amount of time trying to debug it, including trying to see if I could get any sort of response or of the system by using net at, and all of it was a colloidal failure, because I didn't know what was going wrong, or the first thing to do to fix it. After now reading up, the likeliest solution seems to be that changes to Home Assistant made this particular solution unworkable, based on breaking changes that happened between the last time I succeeded and this time. So, option two, using the pyCEC module, turns out to be an epic fail, even though I was successfully able to solve the small problem of how to get pyCEC to use the system library already present from the install rather than having to compile it from scratch and have two potentially conflicting libraries at work with each other.
Still no closer to a working solution, I racked my store of knowledge to try and figure out what else might be useful in this situation. Rattling around in the back of my head was the fact that the voice assistant, Rhasspy, is actually a combination of separated services that pass messages back and forth between each other over a protocol called MQTT. MQTT is a protocol designed for the Internet of Things that doesn't require a lot of overhead and transports things fairly quickly over the network. So long as here's a broker running to direct the messages around, entities can subscribe to MQTT topics to receive messages and publish to those topics. A topic is created on the broker when someone subscribes or published to it first, and so long as there's someone out there listening, the topic stays active on the broker. (I'm sure there's a lot more to it than that, but that's the basics of the idea.)
I already know that I have the stuff to set up an MQTT broker installed on the Raspberry Pi, and I already know that Home Assistant has an integration for working with MQTT brokers and messages, and so, to the Internet we go, to see if someone has helpfully already done the work of creating a program that can take a properly formatted message sent over MQTT and pass it as the parameters that cec-client needs so that the local machine runs the correct command.
There were two immediately available from GitHub, and here's the part where I say how much I appreciate the communities and people who put together projects of their own and then release them for the rest of us to use or mess around with. Open source is amazing as a concept, and I benefit from it so much every day. (And in ways that aren't about doing fancy tricks with a smart house brain.) Of the two immediately available projects for bridging MQTT into cec-client, one of them is much better documented than the other, has the possibility of IR support, and it has a Dockerfile so that I can, when everything is done, stick it in a container and let it do what it does best without having to think too hard about it. The fact that the project itself is a few years old certainly won't generate too many insurmountable problems, right?
Well, it was rough going, shall we say, to get the container to do anything useful, because it wanted to compile its own versions of the libraries, which were two versions behind, rather than using what was already present on the system and getting access to it. It also had in the requirements a specific version of a Python client for MQTT that has had several releases since then. Neither of those things were specifically deal-breakers, as I could adjust the requirements file to grab the newest version of the MQTT client, and I could live with an older version compiled with the correct bindings living in its own happy little container, but it turns out the IR support was the problem - even though the correct library would be snagged, in trying to compile, it would complain about missing headers and abort out. Even though I installed the correct package to the system, the Dockerfile wouldn't find the headers, and so this version stalled out. Which is too bad, but all hope was not lost, as there was a second project that could also do the same thing. It was written in a different language, but the nice thing about it was that I could, y'know, read the source file and attempt to figure out what it could do. So, after installing the correct interpreters for this language, and examining the accompanying shell scripts to build the source into an executable and to run the executable, I gave it a go. The executable compiled without errors, and while it was running, I used a command-line client tool for the broker sending MQTT messages to the topic the documentation said it would subscribe to. After a quick check with the syntax of how to send commands cec-client would recognize, I managed to turn the TV off and back on again using MQTT messages and the bridge!
[Small victory fanfare goes here.]
With the understanding of what the correct commands were going to be to send, I turned my attention to the question of how to set up the switch entity for Home Assistant. Home Assistant has some requirements for its own entities that the bridge was not providing (it was just a pipeline, after all.) Things like setting an entity_id and giving it a name were easy enough, but Home Assistant also needs to understand the state of the switch (on or off) at any given time so that it can display it in the administrative UI, and whether the switch itself is available or unavailable to receive messages. Well, MQTT is good at sending messages back and forth, and it also has a flag that can be set on a message for it to be retained so that when a new subscriber first connects to a topic, they immediately get the retained message. That's a perfect way of setting the correct state when an entity comes online to Home Assistant. And since there's a handy shell script that I can edit that contains the running instructions for the bridge, I can simply choose the topic and use the same command-line program I was testing to send the retained message to the topics I told Home Assistant to subscribe to, which sets both the availability of the switch and the state of the switch.
Except. Availability is easy to do, but I have to figure out whether the TV is on or off at the point the bridge starts up, as, once I have determined that the program works and transmits the correct information, I intend to set the script as a service and have it run on startup for the Pi, so after a power down or a reboot, the bridge will re-establish itself. I don't need the screen on to boot the Pi and have it load and execute all of its automatically-starting services, so it's not a guarantee that the TV will be on when the bridge starts. So, instead of just sending an arbitrary message, I have to get the state of the TV from the CEC bus and send that instead. In my favor, there's a command that I can send to cec-client that reports the power state of the TV when it's run, whether the screen is on or not. Unfortunately for me, because it's supposed to be a friendly program, when I run the command, I get two lines of text back to stdout (standard output, in this case, the console that I'm running the command from) over the course of the entire command, and I only need one word of those two lines, the last one of the second line.
For experienced UNIX and Linux hands, this isn't a problem, and, actually, I have all the tools I need to pull off this feat already installed, which is nice. This takes advantage of the ability of Linux (and probably most POSIX-compliant systems) to pipe. When piping is active, the output of one command is fed as the input into another command. All the time that I've been using cec-client to communicate on the CEC bus, I've actually been piping. The command starts with "echo", a utility that, well, echoes whatever it's been given as input parameters to the standard output. Before echo gets a chance to display what's been given to it as input, though, its output gets tossed into a pipe, Super Mario Brothers-style, so that it emerges as the input for cec-client to take and use as a parameter for its own actions. After cec-client gets done processing the input, it sends its own output to the standard output. (You can actually pull things from files and write to files using the console and piping, so long as you're passing it through the appropriate utilities along the way. Shell scripts are basically sequences of console commands all put together in one file and intended to be executed in sequence, with the ability to engage in logic, set variables, and other such things, if those features are enabled by the shell of choice. Anyway.) So, I would need to add one more pipe to the operation, so that instead of outputting to standard output, the output of cec-client gets pipe-warped to another program, which will further manipulate it and then display its result to standard output. There are more than a few command-line utilities that can be used to parse separated data. I went with awk, because, like any good information professional, I go searching the Internet when I know there's something I should be able to do and someone else has likely answered the question or has posted the documentation. awk takes sufficient parameters that I can tell it to treat its input like it's a set of values separated by spaces, to only look at the second line of the input, and to specifically select the last value of the second line and display / return that. Now, regardless of what the state of the TV is, I can pass that state into the MQTT topic. (Assuming, of course, that cec-client doesn't change what they output to include more lines or to remove any lines. I'm sure there's a more foolproof way of achieving finding the correct word, regardless of where it is in the output, but that probably involves regular expressions, and if you have one problem and you add regular expressions, you usually end up with two problems. Quick, dirty, and working hacks are what we're aiming for here, rather than elegant future-proof code.) Having modified the shell script to pull the power data and publish it to the state topic, before starting the bridge (since after the bridge starts, there's no available connection for cec-client to use from the console) and publishing the availability information to the availability topic, the switch for Home Assistant works! I can turn the bedroom TV on and off again from the Home Assistant, having correctly defined the message payloads to be sent on the on and off actions. This also means that my old scripts to turn the bedroom TV on and off again work, and that I can also use the voice assistant to turn the TV on and off again. So, now I can hands-free turn the TV on and off again from the bedroom iself, no IR remote needed. (And, if I get properly ambitious and learn how to send CEC frames correctly, I can expand the ability of the voice assistant to control all aspects that the CEC bus attached to the Raspberry Pi and the TV support. Like muting. Or sending Hello World messages on the on-screen display. Or similar things.)
[Bigger victory fanfare goes here.]
And that would be flawless victory, barring cleaning up the source code so that the MQTT topics to be used make more human-readable sense to me, and so that I can pinpoint what topics are being used for what devices, in case I need to do a little more MQTT work, or if I start pulling some extra hilarity by using this bridge on a screen that's not always reliable when the IR remote hits it so that I instead let the IR remote give it the ol' college try and then make sure it works by following up with a CEC bus request to go along with it. (Or, well, I would, but it appears that most PC graphics cards don't implement CEC control, like they expect people to be using something other than HDMI to televisions for PC usage and game play. Which is super-weird, because CEC is part of the HDMI spec, and presumably wouldn't take all that much to implement something into it. But maybe we're all expecting to game and watch media on smart televisions instead of having HTPCs attached. I mean, I could, now that I have the means to do so, purchase and install another single-board computer of some sort, like a Pi Zero, and MQTT bridge that for control, but that seems like overkill, honestly, and the IR remote does fine, even if I am grumpy about how it doesn't always catch the signal.)
There's one tiny problem with my implementation so far, and I discovered it pretty quickly when testing the switch in Home Assistant. Touching the switch control in the UI dashboard sent the command to turn on or off, and that worked. But a couple seconds later, the switch would flip back to the previous position it was in. I could double-tap to send the off and then on commands in succession (or on, then off) and get the TV back into sync, but clearly there was something happening that was not intended. Thankfully, it's an easy diagnosis - the UI control only sends the command. Not too soon after, the UI reads the state topic and flips the switch back, because the control command doesn't also send a message to update the state topic! When I implemented in the script to send a message to the state topic as well as the command topic, the UI element switched to the appropriate state and stayed there. So Home Assistant expects the switch to receive the command, and then publish and update to its state on its own as well as implementing the command. To properly implement that decision, I had to stare at the source code for the executable for quite some time, and use my MQTT subscription to inspect the traffic going back and forth so that I could see what was being passed through. That gave me the frames that I would need to look for to get the program to fire off an update to the state topic, but it took me an embarassingly long time to look at the function that was being called and what was being evaluated (the length of an array) to recognize what was happening across the bus and how to add my own logic to the cases already being evaluated so that I would get a message to the state topic as well as the message across the bus to the TV. Once I got that figured out, though, and then made sure all the typos had been removed from all the topic names that I wanted transmission and reception over, and then worked around some edge cases about making sure that Home Assistant would always have a state message when it connected, I have it under control and working exactly properly.
[Right and Proper Victory Theme Goes Here!]
Once again, dirty hacks done dirt cheap and successfully, based on looking at code and then trying things until understanding appeared. It took hours to get everything in place for what seems to be a tiny amount of actual work done (some code lines changed, others added, less than two dozen lines total, I think, to the actual programs, and then another dozen of the service template I borrowed from someone else to make it happen on startup and modified to run the program I wanted.) It doesn't feel like a great and powerful accomplishment to have succeeded this time around, either, perhaps because of all the typo correction and the having modified someone else's heavy lifting instead of generating something myself in the language of my choosing. Except, of course, that I would almost certainly be importing modules that someone else has created even if I were creating my own script, so I could go as far down as I like in that turtle pile until we get to "well, if you're not manipulating the inodes by hand with magnets, then you're not really coding." Someone put their code out there, I took it and made it work for me. That, theoretically, is software and/or systems engineering. But much like creating art doodles or sketches or the craft projects or the baking and cooking that I've been doing, I can always find some reason somewhere to say that I didn't do it the Right and Proper Way, which almost always seems to be stuck in my mind as "from scratch, with no help or recipes from anyone else, and with no already-prepared ingredients," since that's apparently the mark of True Artistry with the thing. Even though I think that it's not very intelligent to test student memorization of things when in the real world applications of what they will be doing, they'll have computers or reference works or colleagues to help them out with the correct measurements and procedures. I think it might be echoes of Giftedness equating the True Artness with already knowing or lack of effort and time put in to produce flawless work. Even though the important things often take effort much more than they need brilliance or knowing it all before beginning.
And, having finished with this project, there's another one or two of them coming around the corner, to try and replicate, as best as possible, some of the functionality with the lights that got lost when we stopped using the manufacturer's API and its links into other web-based services and instead brought them under local control so they would be reliable, instead. It's entirely possible that many of the things that were in use can be replicated, based on sensors already in place, and other ones, well, now might be the time where we start pulling in specific data from someone else's published APIs and manipulating it for our purposes.
Right now, however, we get to enjoy a saga of doing things the wrong way repeatedly until something gets done correctly and it works. I have an old television that my ex had me buy for myself so that the older, heavier model didn't have to make a trip with me (or so that I wouldn't feel like I was only spending money on things for her, or both) that still works excellently for display reasons, except for one tiny thing: the Infrared (IR) sensor on it is busted. I have no idea when this happened, but that's the reality of it. With a working IR sensor, controlling this television from Home Assistant would be much easier, as there's already a trainable IR remote in the same room as the TV.
Assisting the cause is that this otherwise non-smart television has a Raspberry Pi single-board computer attached to it. (The Pi already provides a satellite instance of the voice assistant, so it's already part of the smart home infrastructure.) All of the Raspberry Pis have the ability, with the correct distribution packages, to use HDMI-CEC, a part of the HDMI specification that allows commands to be sent over an HDMI cable to compatible displays and systems to control those connected systems. It's most commonly used for things like turning on an audio system along with a TV or monitor, so that one power button gets the whole system up and running. The TV has a working HDMI-CEC bus on it, so the Pi can send commands over it to turn the TV on and off, change the volume, mute it, etc. It should be able to do basically anything that the CEC-O-MATIC says is part of the specification. Rather than have to send specific frames for common activities, there are some commands that cec-client can send as words instead. So, it's easy enough to scan the HDMI-CEC bus and figure out the addresses of the Pi and the TV, and to test that the bus works using specific syntax to format commands and pass them as arguments into cec-client. From the command line of the local machine, things work just fine. TV turns off and on again with those commands from the local console.
With local control established as working, at this point, there are options on how to turn that local control into remote access from the Home Assistant. Perhaps the most direct way would be to allow Home Assistant to access the Pi and run the shell command locally. This would require setting up a secure shell connection between the two machines. However, Home assistant is not equipped to transmit a username and password for authentication and instead has to use pregenerated keys copied to the correct locations on both machines to allow for the connection. It's a hassle, even though it's secure, and the first time I tried this, it never worked how I wanted it to, so I wasn't going to try that again.
A less direct method, but one that looked like it had promise, was to use a module (pyCEC) that could hook into Home Assistant's own HDMI-CEC integration by providing a bridge over the network so that Home assistant could see the remote CEC bus as if it were local and manipulated it in the same way. On a previous version of Home Assistant and the Pi, I managed to successfully set up the bridge and use it for remote control, although it requested compiling a library from source with correct bindings to work as a condition of sauces. I knew, however, that the relevant library had already been installed from the package manager on this iteration of the Pi, so it seemed wasteful to compile something when it was already there. The missing bindings, so that the library would work with Python 3, were contained in a different package available from the package manager, ask once installed, the remote bridge would work, or so I thought.
It did not, in fact, work like before, and I spent a significant amount of time trying to debug it, including trying to see if I could get any sort of response or of the system by using net at, and all of it was a colloidal failure, because I didn't know what was going wrong, or the first thing to do to fix it. After now reading up, the likeliest solution seems to be that changes to Home Assistant made this particular solution unworkable, based on breaking changes that happened between the last time I succeeded and this time. So, option two, using the pyCEC module, turns out to be an epic fail, even though I was successfully able to solve the small problem of how to get pyCEC to use the system library already present from the install rather than having to compile it from scratch and have two potentially conflicting libraries at work with each other.
Still no closer to a working solution, I racked my store of knowledge to try and figure out what else might be useful in this situation. Rattling around in the back of my head was the fact that the voice assistant, Rhasspy, is actually a combination of separated services that pass messages back and forth between each other over a protocol called MQTT. MQTT is a protocol designed for the Internet of Things that doesn't require a lot of overhead and transports things fairly quickly over the network. So long as here's a broker running to direct the messages around, entities can subscribe to MQTT topics to receive messages and publish to those topics. A topic is created on the broker when someone subscribes or published to it first, and so long as there's someone out there listening, the topic stays active on the broker. (I'm sure there's a lot more to it than that, but that's the basics of the idea.)
I already know that I have the stuff to set up an MQTT broker installed on the Raspberry Pi, and I already know that Home Assistant has an integration for working with MQTT brokers and messages, and so, to the Internet we go, to see if someone has helpfully already done the work of creating a program that can take a properly formatted message sent over MQTT and pass it as the parameters that cec-client needs so that the local machine runs the correct command.
There were two immediately available from GitHub, and here's the part where I say how much I appreciate the communities and people who put together projects of their own and then release them for the rest of us to use or mess around with. Open source is amazing as a concept, and I benefit from it so much every day. (And in ways that aren't about doing fancy tricks with a smart house brain.) Of the two immediately available projects for bridging MQTT into cec-client, one of them is much better documented than the other, has the possibility of IR support, and it has a Dockerfile so that I can, when everything is done, stick it in a container and let it do what it does best without having to think too hard about it. The fact that the project itself is a few years old certainly won't generate too many insurmountable problems, right?
Well, it was rough going, shall we say, to get the container to do anything useful, because it wanted to compile its own versions of the libraries, which were two versions behind, rather than using what was already present on the system and getting access to it. It also had in the requirements a specific version of a Python client for MQTT that has had several releases since then. Neither of those things were specifically deal-breakers, as I could adjust the requirements file to grab the newest version of the MQTT client, and I could live with an older version compiled with the correct bindings living in its own happy little container, but it turns out the IR support was the problem - even though the correct library would be snagged, in trying to compile, it would complain about missing headers and abort out. Even though I installed the correct package to the system, the Dockerfile wouldn't find the headers, and so this version stalled out. Which is too bad, but all hope was not lost, as there was a second project that could also do the same thing. It was written in a different language, but the nice thing about it was that I could, y'know, read the source file and attempt to figure out what it could do. So, after installing the correct interpreters for this language, and examining the accompanying shell scripts to build the source into an executable and to run the executable, I gave it a go. The executable compiled without errors, and while it was running, I used a command-line client tool for the broker sending MQTT messages to the topic the documentation said it would subscribe to. After a quick check with the syntax of how to send commands cec-client would recognize, I managed to turn the TV off and back on again using MQTT messages and the bridge!
[Small victory fanfare goes here.]
With the understanding of what the correct commands were going to be to send, I turned my attention to the question of how to set up the switch entity for Home Assistant. Home Assistant has some requirements for its own entities that the bridge was not providing (it was just a pipeline, after all.) Things like setting an entity_id and giving it a name were easy enough, but Home Assistant also needs to understand the state of the switch (on or off) at any given time so that it can display it in the administrative UI, and whether the switch itself is available or unavailable to receive messages. Well, MQTT is good at sending messages back and forth, and it also has a flag that can be set on a message for it to be retained so that when a new subscriber first connects to a topic, they immediately get the retained message. That's a perfect way of setting the correct state when an entity comes online to Home Assistant. And since there's a handy shell script that I can edit that contains the running instructions for the bridge, I can simply choose the topic and use the same command-line program I was testing to send the retained message to the topics I told Home Assistant to subscribe to, which sets both the availability of the switch and the state of the switch.
Except. Availability is easy to do, but I have to figure out whether the TV is on or off at the point the bridge starts up, as, once I have determined that the program works and transmits the correct information, I intend to set the script as a service and have it run on startup for the Pi, so after a power down or a reboot, the bridge will re-establish itself. I don't need the screen on to boot the Pi and have it load and execute all of its automatically-starting services, so it's not a guarantee that the TV will be on when the bridge starts. So, instead of just sending an arbitrary message, I have to get the state of the TV from the CEC bus and send that instead. In my favor, there's a command that I can send to cec-client that reports the power state of the TV when it's run, whether the screen is on or not. Unfortunately for me, because it's supposed to be a friendly program, when I run the command, I get two lines of text back to stdout (standard output, in this case, the console that I'm running the command from) over the course of the entire command, and I only need one word of those two lines, the last one of the second line.
For experienced UNIX and Linux hands, this isn't a problem, and, actually, I have all the tools I need to pull off this feat already installed, which is nice. This takes advantage of the ability of Linux (and probably most POSIX-compliant systems) to pipe. When piping is active, the output of one command is fed as the input into another command. All the time that I've been using cec-client to communicate on the CEC bus, I've actually been piping. The command starts with "echo", a utility that, well, echoes whatever it's been given as input parameters to the standard output. Before echo gets a chance to display what's been given to it as input, though, its output gets tossed into a pipe, Super Mario Brothers-style, so that it emerges as the input for cec-client to take and use as a parameter for its own actions. After cec-client gets done processing the input, it sends its own output to the standard output. (You can actually pull things from files and write to files using the console and piping, so long as you're passing it through the appropriate utilities along the way. Shell scripts are basically sequences of console commands all put together in one file and intended to be executed in sequence, with the ability to engage in logic, set variables, and other such things, if those features are enabled by the shell of choice. Anyway.) So, I would need to add one more pipe to the operation, so that instead of outputting to standard output, the output of cec-client gets pipe-warped to another program, which will further manipulate it and then display its result to standard output. There are more than a few command-line utilities that can be used to parse separated data. I went with awk, because, like any good information professional, I go searching the Internet when I know there's something I should be able to do and someone else has likely answered the question or has posted the documentation. awk takes sufficient parameters that I can tell it to treat its input like it's a set of values separated by spaces, to only look at the second line of the input, and to specifically select the last value of the second line and display / return that. Now, regardless of what the state of the TV is, I can pass that state into the MQTT topic. (Assuming, of course, that cec-client doesn't change what they output to include more lines or to remove any lines. I'm sure there's a more foolproof way of achieving finding the correct word, regardless of where it is in the output, but that probably involves regular expressions, and if you have one problem and you add regular expressions, you usually end up with two problems. Quick, dirty, and working hacks are what we're aiming for here, rather than elegant future-proof code.) Having modified the shell script to pull the power data and publish it to the state topic, before starting the bridge (since after the bridge starts, there's no available connection for cec-client to use from the console) and publishing the availability information to the availability topic, the switch for Home Assistant works! I can turn the bedroom TV on and off again from the Home Assistant, having correctly defined the message payloads to be sent on the on and off actions. This also means that my old scripts to turn the bedroom TV on and off again work, and that I can also use the voice assistant to turn the TV on and off again. So, now I can hands-free turn the TV on and off again from the bedroom iself, no IR remote needed. (And, if I get properly ambitious and learn how to send CEC frames correctly, I can expand the ability of the voice assistant to control all aspects that the CEC bus attached to the Raspberry Pi and the TV support. Like muting. Or sending Hello World messages on the on-screen display. Or similar things.)
[Bigger victory fanfare goes here.]
And that would be flawless victory, barring cleaning up the source code so that the MQTT topics to be used make more human-readable sense to me, and so that I can pinpoint what topics are being used for what devices, in case I need to do a little more MQTT work, or if I start pulling some extra hilarity by using this bridge on a screen that's not always reliable when the IR remote hits it so that I instead let the IR remote give it the ol' college try and then make sure it works by following up with a CEC bus request to go along with it. (Or, well, I would, but it appears that most PC graphics cards don't implement CEC control, like they expect people to be using something other than HDMI to televisions for PC usage and game play. Which is super-weird, because CEC is part of the HDMI spec, and presumably wouldn't take all that much to implement something into it. But maybe we're all expecting to game and watch media on smart televisions instead of having HTPCs attached. I mean, I could, now that I have the means to do so, purchase and install another single-board computer of some sort, like a Pi Zero, and MQTT bridge that for control, but that seems like overkill, honestly, and the IR remote does fine, even if I am grumpy about how it doesn't always catch the signal.)
There's one tiny problem with my implementation so far, and I discovered it pretty quickly when testing the switch in Home Assistant. Touching the switch control in the UI dashboard sent the command to turn on or off, and that worked. But a couple seconds later, the switch would flip back to the previous position it was in. I could double-tap to send the off and then on commands in succession (or on, then off) and get the TV back into sync, but clearly there was something happening that was not intended. Thankfully, it's an easy diagnosis - the UI control only sends the command. Not too soon after, the UI reads the state topic and flips the switch back, because the control command doesn't also send a message to update the state topic! When I implemented in the script to send a message to the state topic as well as the command topic, the UI element switched to the appropriate state and stayed there. So Home Assistant expects the switch to receive the command, and then publish and update to its state on its own as well as implementing the command. To properly implement that decision, I had to stare at the source code for the executable for quite some time, and use my MQTT subscription to inspect the traffic going back and forth so that I could see what was being passed through. That gave me the frames that I would need to look for to get the program to fire off an update to the state topic, but it took me an embarassingly long time to look at the function that was being called and what was being evaluated (the length of an array) to recognize what was happening across the bus and how to add my own logic to the cases already being evaluated so that I would get a message to the state topic as well as the message across the bus to the TV. Once I got that figured out, though, and then made sure all the typos had been removed from all the topic names that I wanted transmission and reception over, and then worked around some edge cases about making sure that Home Assistant would always have a state message when it connected, I have it under control and working exactly properly.
[Right and Proper Victory Theme Goes Here!]
Once again, dirty hacks done dirt cheap and successfully, based on looking at code and then trying things until understanding appeared. It took hours to get everything in place for what seems to be a tiny amount of actual work done (some code lines changed, others added, less than two dozen lines total, I think, to the actual programs, and then another dozen of the service template I borrowed from someone else to make it happen on startup and modified to run the program I wanted.) It doesn't feel like a great and powerful accomplishment to have succeeded this time around, either, perhaps because of all the typo correction and the having modified someone else's heavy lifting instead of generating something myself in the language of my choosing. Except, of course, that I would almost certainly be importing modules that someone else has created even if I were creating my own script, so I could go as far down as I like in that turtle pile until we get to "well, if you're not manipulating the inodes by hand with magnets, then you're not really coding." Someone put their code out there, I took it and made it work for me. That, theoretically, is software and/or systems engineering. But much like creating art doodles or sketches or the craft projects or the baking and cooking that I've been doing, I can always find some reason somewhere to say that I didn't do it the Right and Proper Way, which almost always seems to be stuck in my mind as "from scratch, with no help or recipes from anyone else, and with no already-prepared ingredients," since that's apparently the mark of True Artistry with the thing. Even though I think that it's not very intelligent to test student memorization of things when in the real world applications of what they will be doing, they'll have computers or reference works or colleagues to help them out with the correct measurements and procedures. I think it might be echoes of Giftedness equating the True Artness with already knowing or lack of effort and time put in to produce flawless work. Even though the important things often take effort much more than they need brilliance or knowing it all before beginning.
And, having finished with this project, there's another one or two of them coming around the corner, to try and replicate, as best as possible, some of the functionality with the lights that got lost when we stopped using the manufacturer's API and its links into other web-based services and instead brought them under local control so they would be reliable, instead. It's entirely possible that many of the things that were in use can be replicated, based on sensors already in place, and other ones, well, now might be the time where we start pulling in specific data from someone else's published APIs and manipulating it for our purposes.
the requested typo reminder
Date: 2022-04-17 05:48 am (UTC)Re: the requested typo reminder
Date: 2022-04-17 05:54 am (UTC)no subject
Date: 2022-04-17 11:05 am (UTC)no subject
Date: 2022-04-17 08:01 pm (UTC)no subject
Date: 2022-04-17 08:34 pm (UTC)no subject
Date: 2022-04-17 09:37 pm (UTC)no subject
Date: 2022-04-17 11:43 pm (UTC)