Control Hyperion through a small web server

  • Looked all over for a way to control Hyperion through a web call, primarily so I could control from WebCore in SmartThings. It can't send raw TCP. Could find anything, so rolled my own. Thought I'd share in case in helps anyone else.


    1) Add a couple python modules on your Raspi that runs hyperion.


    pip install bottle
    pip install bottledaemon


    2) The python script that runs the web server and add endpoints for color and effects:


    from bottledaemon import daemon_run
    from bottle import route, run, template
    import subprocess



    @route('/color/<colorid>')
    def index(colorid):
    subprocess.check_output(['/usr/bin/hyperion-remote', '--color', colorid])
    return "done"


    @route('/effect/<effectname>')
    def index(effectname):
    subprocess.check_output(['/usr/bin/hyperion-remote', '--effect', effectname])
    return "done"


    @route('/clearall')
    def index():
    subprocess.check_output(['/usr/bin/hyperion-remote', '--clearall'])
    return "done"


    if __name__ == "__main__":
    daemon_run(host="0.0.0.0", port="8080")


    3) Start the python script using nohup so you can close your connection and it keep running.


    nohup /usr/bin/python /home/pi/Documents/hyperionweb.py start


    4) make a standard http request to control.


    http://192.168.2.71:8080/effect/Cold%20mood%20blobs
    http://192.168.2.71:8080/color/ff0000
    http://192.168.2.71:8080/clearall




    Hopefully this is useful to someone. And hopefully I didn't overlook something completely obvious and do it the hard way.


    milhouse

  • I finally got around to trying this but I'm running OpenElec and looks like you can't install much in this OS. Is there any other solution to making remote requests to Hyperion via URL?

  • I think this is exactly what i am looking for, but am struggling to get it working. I'm wanting to tie this into to google home assistant. What I am looking for is a web address to give to the home assistant to hit so that it will change the lights. I roughly understand what is going on in the script written above, but am a little lost when it comes to the nohup section. The other issue i have is that port 8080 is already applied to another device in my household. Would i be okay to use 8081? Can i just swap that in the code? Also do i need to put my pi's ip address in the 0.0.0.0 section of the code?


    Any help you can provide would be greatly appreciated. I've had an ambilight setup around my tv for awhile now. I am now in the process of building a couch rail that i am embedding 9m of LED into. This is what I would like to set with google assitant ("Hey google, set couch to Green Mood Blobs.").

  • So i did eventually pseudo get this working. It was having issues when i put both the effect route and the color route in. If i left it at 1 it ran fine and i was able to hit the url in a web browser and the lights would change. I thought at that point i was golden to hook it into ifttt to do it via voice control. However I quickly realized my port was only open on my local network as my ip was only static to my router and not to my ISP which is giving my router a dynamic ip. Therefore the ifttt servers were unable to talk to my pi to change the lights :( . Oh well, it was really just a "nice to have" anyways.

  • Sorry for the delayed reply. Travelling this week.


    You should not need to change the IP addresss 0.0.0.0. That just lets it accept on any network connect. If you had multiple, you could specift which address it should listen on. Port doesn't matter - you should be able to set any non-conflicting port for it to listen on (the 8080 in my code snippet). Obviosuly, you'd change the URLs to the same port.


    Set up port forwarding on your router for that port so an external call to your (external) IP address would go to your pi.


    Most ISPs don't actually change your IP address very often - my usually lasts for months without change. But if it's a problem look into a dynamic dns service so you could call by address instead of IP.

  • Any others successfully set this up? I've done everything by the book but getting nothing when hitting the urls. Is there somewhere I could look at a log to see what's going on. Everything was installed successfully and I've got my python script formatted correctly as well.


    UPDATE: I think I got it!! Guess I just had to restart my hyperion. So far all is working. Thanks!

  • So now that I've got this working, can anyone share some use cases? For me, this setup is huge bc I've been looking for a way to "turn off" my ambilight with Alexa. By turn off, I mean set it to black bc there's still HDMI signal from my fireTV even with the TV powered off.


    My thinking is that I'll make a virtual momentary push switch, and in webcore make the GET request to the url which calls black. Then I can just add it to Alexa.


    I'd love to be able to call effects too, but not interested in a switch for every effect. I like milhouse's random option.

  • Yes, you could have a virtual switch available to Alexa. Webcore could respond to the switch changes to off trigger, make a web call to the clearall endpoint, and turn the virtual switch back on (so it's ready agin for the turn off). Or a momentary switch.


    Like you said - could be a lot of virtual switches if you wanted finer control. And you'd have to pay attention to priorities in hyperion, in case you wanted to override the HDMI signlat with an effect for example.


    I use the random effect (of my favorite effects) so it's just part of my outdoor lighting routines. On at sunset -30, off at 11:00pm.

  • So I just switched my whole system over to Orbi mesh. Now I can't get this setup to work! I've checked everything. IP is static, hyperion Pi is connected fine. Is there something I need to do with Orbi to allow me to make the call? My hyperion android remote app works fine from my phone.


  • Any ideas here? I just started over with everything and still an issue. Do I need to enable some port forwarding or change my Orbi settings? I fee like something is blocking this.

  • If you are sure the script is actually running (e.g. does it work from the Pi itself through a browser or curl), then I can only assume you are right and it's the orbi. I've never seen a consumer grade router that blocks anything on the LAN side, though.


    Should only need port forwarding if you want things to be accessible from outside your home network.


    In the python script, did you leave the 0.0.0.0 address or change it to the static IP? If you leave at 0.0.0.0 then it should accept connections on all IPs (like if the pi is on wireless and wired networks).


    Does ifconfig show you the IP address you think you have assigned?

  • Script is/was definitely running. Calling from the pi itself didn't seem to work either. But then something odd happened. I kept trying to call directly from Chrome on my mac. I gave up but left a page opened. About a half hour later my TV lights just popped on. Some sort of bad delay or maybe the router firewall? Not sure. IP address was fine, no change in anything. Very weird.


    I'm no dummy, but not smart enough to try and pinpoint on the network what is actually happening. I'm also planning to setup PiHole on another machine so wondering if I'll run into issues.

  • I wonder if the script is not starting up correctly because of some leftover bottle files from a previous crash. That would be files that start with bottle* AND a file that seems to include the machine name.
    pi@Pi-Attic:~ $ ls
    bottle.log Documents Pictures Videos
    bottle.pid Downloads Public
    bottle.pid.lock Music python_games
    Desktop Pi-Attic-76f9b8c0.517-158751035 Templates


    In my shell script that starts the webserver, I clean up any potential leftovers first, then start the hyperion web server.


    #!/bin/sh
    rm bottle* -f
    rm Pi-Attic* -f
    nohup /usr/bin/python /home/pi/Documents/hyperionweb.py start



    Give that a try - stop the bottle web server ("hyperionweb.py stop"), clean up the files above, then start again. Give it a minute to get running, then try calling it.

  • Awesome, I will try this out in the next couple days. I probably missed this, but should I create a script like yours and have it run at bootup? My hyperion auto starts when I reboot. I assume I could control the order?


    Ideally, what I'd like to do is maybe setup a cron to reboot every couple days in the middle of the night and run your cleanup, then have hyperion start.


    Thanks for the help on this.

  • Well, that's something I never quite figured out how to do. I don't have the webserver script run on startup - never managed to get it to work right. I manually run my shell script (the 4 line script above, rm + nohup python lines) every time I reboot - only every couple of months, so not very labor intensive. If you are going to reboot regularly you'd probably want to get it to start automatically. Why a regular reboot at all? My pi runs for months without issue. The file cleanup I do is simply because the bottle webserver doesn't run properly if I don't delete them first - has nothing to do with actually needing a regular restart.


    If it ran on startup, then you'd probably skip the nohup part since it would be independent of a logged in user. But I have no idea where the bottle files would go. Can't remember exactly what problems I had trying to get it to run on boot. If you figure out how to do it, let me know please!


    Startup order actually shouldn't matter - the webserver doesn't actually interface directly with hyperion, it just runs a command line when called.

  • So i am trying to get back to making this work through my google home mini. I still have to figure out the getting the google home mini to communicate in my network, but fairly certain i can get that. I have it up and running to where i can hit a webaddress on my computer to trigger an effect. Problem being is that it only works if i have just the effect or just the color script in it. As soon as i try to include the clearall or both color and effect in it, i get errors trying to run the CouchSite.py. (its a webserver to control my LEDs embedded into my couch drink rail)


    Here is what i currently have. I dont know why but when i was working previously i got away from the daemon stuff and am using some for of app. Im not well versed in any of this and trying to learn as i go.


    import subprocess


    from flask import Flask


    app = Flask(__name__)



    @app.route('/effect/<effectname>')


    def index(effectname):


    subprocess.check_output(['/usr/bin/hyperion-remote', '--effect', effectname])


    return"<html><body><h1>done</h1></body></html>"



    @app.route('/clearall')


    def index():


    subprocess.check_output(['/usr/bin/hyperion-remote', '--clearall'])


    return"<html><body><h1>clear</h1></body></html>"



    if __name__ == "__main__":


    app.run(host='0.0.0.0', port='8081')



    When i try to run the script i get this....


    Traceback (most recent call last):


    File "CouchSite.py", line 10, in <module>


    @app.route('/clearall')


    File "/usr/lib/python3/dist-packages/flask/app.py", line 1080, in decorator


    self.add_url_rule(rule, endpoint, f, **options)


    File "/usr/lib/python3/dist-packages/flask/app.py", line 64, in wrapper_func


    return f(self, *args, **kwargs)


    File "/usr/lib/python3/dist-packages/flask/app.py", line 1051, in add_url_rule


    'existing endpoint function: %s' % endpoint)


    AssertionError: View function mapping is overwriting an existing endpoint function: index



    Any ideas of what i am missing. I feel like its probably something stupid and that i am close. Any help is appreciated, thank you!

  • Just going to make a stab in the dark, based on this error line:
    AssertionError: View function mapping is overwriting an existing endpoint function: index


    I wonder if flask doesn't like the same variable name used more than once. Maybe change each def to be something different?
    @route('/color/<colorid>')
    def indexc(colorid):
    subprocess.check_output(['/usr/bin/hyperion-remote', '--color', colorid])
    return "done"
    @route('/effect/<effectname>')
    def indexe(effectname):
    subprocess.check_output(['/usr/bin/hyperion-remote', '--effect', effectname])
    return "done"
    @route('/clearall')
    def indexclear():
    subprocess.check_output(['/usr/bin/hyperion-remote', '--clearall'])
    return "done"

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!