No internet connection
  1. Home
  2. General

Power Control/Switching

By Jeremy Beall @jezzab
    2021-12-28 21:51:32.781Z

    Hi,
    Using the TinyPilot but wanted some power control for one of my servers (it doesnt have IPMI unfortunately, its a consumer motherboard) so I thought I would have a dabble and I didnt really want to go all out and start wiring up relays to GPIOs etc so I went with what I had laying around and went wireless:

    Server plugged into a TP-Link HS110 (you could use a HS100 or other similar wifi power switch)
    https://www.tp-link.com/au/home-networking/smart-plug/hs110/

    And a little python magic to switch it off and on based on this repo:
    https://github.com/ajay10000/TP-Link-HS110

    Maybe it might be of interest to someone someday, so I thought I would post it here

    Jeremy

    • 8 replies
    1. @fft2021-12-29 04:48:41.919Z

      Hi,
      I use the shelly plugs https://shop.shelly.cloud/shelly-plug-s-wifi-smart-home-automation#62 instead of the tp-link ones. It takes less space in a german (european) wall socket. The user interface is really easy and they provide a rest api: https://shelly-api-docs.shelly.cloud/gen1/#shelly-plug-plugs-relay-0 they also have US plugs. So a simply curl call does in my home office all my needed magic on a fingertips.
      I am not related to shelly in any way, just a happy client, and I liked the idea you had remotely switching on/off a machine.
      Jürgen

      1. In reply tojezzab:

        That's really cool, @jezzab. Thanks for sharing this!

        How difficult was it to code this up? I'm interested in making it easier for users to extend TinyPilot's functionality, so any feedback about your experience modifying the code would be helpful.

        1. J
          In reply tojezzab:
          Jeremy Beall @jezzab
            2021-12-29 20:50:58.577Z2021-12-29 20:59:47.933Z

            There is probably an easier way to do it but this is the path I took. Hardest part was working out how everything ties together and because I wanted a dialog box with options.
            It would be nice to even just have a menu option: Run External Script or something like that

            I created two new PHP files that would call the scripts with different parameters (you could no doubt just do it with one file as well if you just wanted to call a single script and bypass the dialog box all together):
            /opt/tinypilot/app/static/rempowoff.php:

            <?php
                echo exec('python3 /opt/tinypilot/app/hs110.py -c off');
                $loc = "http://" . $_SERVER['SERVER_ADDR'];
                echo "<script>window.location.href = '$loc';</script>"
            ?>
            

            /opt/tinypilot/app/static/rempowon.php:

            <?php
                echo exec('python3 /opt/tinypilot/app/hs110.py -c on');
                $loc = "http://" . $_SERVER['SERVER_ADDR'];
                echo "<script>window.location.href = '$loc';</script>"
            ?>
            

            Created a new dialog box which I just based on the TinyPilot control one:
            /opt/tinypilot/app/templates/custom-elements/rem-power-dialog.html:

            <template id="rem-power-dialog-template">
              <style>
                @import "css/style.css";
                @import "css/button.css";
            
                #prompt,
                #restarting,
                #shutting-down,
                #shutdown-complete {
                  display: none;
                }
            
                :host([state="prompt"]) #prompt {
                  display: block;
                }
              </style>
              <div id="rem-power-confirmation-panel" class="overlay">
                    <div>
                      <h3>Control Power on Remote Device?</h3>
                      <p>
                            Note that this will power up or  down <strong>The Remote Device</strong>, not the Tiny Pilot Pi to which it is attached.
                      </p>
                      <a href = "rempowon.php">
                      <button id="rem-power-on" class="btn-danger" type="button">
                            Power On
                      </button></a>
                      <a href = "rempowoff.php">
                      <button id="rem-power-off" class="btn-danger" type="button">
                            Power Off
                      </button></a>
                      <button id="cancel-rem-power" type="button">Cancel</button>
                    </div>
              </div>
            </template>
            
            <script type="module">
              import { DialogClosedEvent, DialogFailedEvent } from "/js/events.js";
              import { shutdown } from "/js/controllers.js";
            
              (function () {
                const template = document.querySelector("#rem-power-dialog-template");
            
                customElements.define(
                  "rem-power-dialog",
                  class extends HTMLElement {
                    constructor() {
                      super();
                    }
            
                    connectedCallback() {
                      this.attachShadow({ mode: "open" }).appendChild(
                        template.content.cloneNode(true)
                      );
                      this.state = "prompt";
            
                      this.shadowRoot
                        .getElementById("cancel-rem-power")
                        .addEventListener("click", () => {
                          this.dispatchEvent(new DialogClosedEvent());
                        });
                    }
            
                    get state() {
                      return this.getAttribute("state");
                    }
            
                    set state(newValue) {
                      this.setAttribute("state", newValue);
                    }
                  }
                );
              })();
            </script>
            

            Then edited the menu bar for another option and to call the dialog box by adding another rem-power-btn "button" and item:
            /opt/tinypilot/app/templates/custom-elements/menu-bar.html:
            Here after the Keyboard Shortcuts button:

            ...
                      <a>Keyboard Shortcuts</a>
                      <ul class="items">
                        <li class="item">
                          <a id="ctrl-alt-del-btn">Ctrl + Alt + Del</a>
                        </li>
                      </ul>
                    </li>
                    <li class="item">
                      <a id="rem-power-btn">Remote Power Control</a>
                    </li>
                  </ul>
                </li>
            ...
            

            And here after the ctrl-alt-del-btn request:

            ...
                        "ctrl-alt-del-btn": "ctrl-alt-del-requested",
                        "rem-power-btn": "rem-power-dialog-requested"
                      };
            ...
            

            Then added the rem-power-dialog overlay to the main index file after the shutdown overlay:
            /opt/tinypilot/app/templates/index.html:

            ...
                    <overlay-panel id="shutdown-overlay">
                      <shutdown-dialog id="shutdown-dialog"></shutdown-dialog>
                    </overlay-panel>
                    <overlay-panel id="rem-power-overlay">
                      <rem-power-dialog id="rem-power-dialog"></rem-power-dialog>
                    </overlay-panel>
            ...
            

            And lastly I had to edit the main app Javascript file to add another event listener after the shutdown-dialog-requested one:
            /opt/tinypilot/app/static/js/app.js:

            menuBar.addEventListener("shutdown-dialog-requested", () => {
              document.getElementById("shutdown-overlay").show();
            });
            menuBar.addEventListener("rem-power-dialog-requested", () => {
              document.getElementById("rem-power-overlay").show();
            });
            
            1. Cool, thanks for sharing!

              You could simplify a bit by dropping PHP from the mix. The backend is Python and your hs110.py script is Python, so you should be able to add a route to api.py and then just import hs110 as a module instead of shelling out to its CLI.

              1. JJeremy Beall @jezzab
                  2021-12-30 19:13:36.911Z

                  Ok cool. I'll look into it

              2. E
                In reply tojezzab:
                @ezekielnewren
                  2022-08-26 07:27:07.352Z

                  There is an expansion board with 4 relay switches for the raspberry pi. I think it would be great to have a tiny pilot version that had this expansion board built in. In fact you can stack up to 4 of these board to control 16 relay switches. This is the solution that I'm going with.

                  https://www.amazon.com/gp/product/B07Y54FKC6

                  1. Diego @diego
                      2022-08-26 23:56:48.110Z

                      Hello @ezekielnewren - Thank you for you feedback, very much appreciated! I understand this would be an amazing feature but unfortunately, this has not been requested by many users, and there are no plans to incorporate extra hardware into the TinyPilot Voyager 2 line, at least not in the near future. It is worthwile noting however, that TinyPilot supports Wake On Lan.

                    • Progress
                    • B
                      @barrym
                        2023-08-02 04:54:32.888Z

                        For an alternative solution, check out this usbrelay approach I posted.