Home Assistant - BMC integration
# │forum
t
Hi All Has anyone written any cards / sensors / etc to show the BMC and node states in a Home Assistant card? No point reinventing the wheel if someone has done it already. It theoretically shouldn't be too hard, given the underlying API spits out json and HA can read this, but I'm struggling to setup sensors with each node's power state, let alone more complex stuff. I've been trying the built in rest integration and my main issue is unfamiliarity with HA's json-parsing syntax (essentially how to dispose of the response and result wrappers), rather than authentication or other things. An alternate way would be to use a command_line sensor (as I'm much more familiar with jq) but this seems more complex than necessary.
b
I unfortunately have no way to test/validate it right now (since my Turing board doesn't seem to like my network and I lose the connection to it after a few weeks), but I had this home assistant configuration set up: configuration.yaml:
Copy code
yaml
rest: !include_dir_merge_list rest/
rest/turing_nodes_info.yaml
Copy code
yaml
- resource: https://<ip-address>/api/bmc?opt=get&type=nodeinfo
  authentication: basic
  username: <username>
  password: <password>
  verify_ssl: false
  sensor:
    - name: Turing Pi Node 1 Info
      value_template: "{{ value_json['response'][0]['result'][0]['node1'] }}"
    - name: Turing Pi Node 2 Info
      value_template: "{{ value_json['response'][0]['result'][0]['node2'] }}"
    - name: Turing Pi Node 3 Info
      value_template: "{{ value_json['response'][0]['result'][0]['node3'] }}"
    - name: Turing Pi Node 4 Info
      value_template: "{{ value_json['response'][0]['result'][0]['node4'] }}"
rest/turing_nodes_power.yaml
Copy code
yaml
- resource: https://<ip-address>/api/bmc?opt=get&type=power
  authentication: basic
  username: <username>
  password: <password>
  verify_ssl: false
  sensor:
    - name: Turing Pi Node 1 Info
      value_template: "{{ value_json['response'][0]['result'][0]['node1'] }}"
    - name: Turing Pi Node 2 Info
      value_template: "{{ value_json['response'][0]['result'][0]['node2'] }}"
    - name: Turing Pi Node 3 Info
      value_template: "{{ value_json['response'][0]['result'][0]['node3'] }}"
    - name: Turing Pi Node 4 Info
      value_template: "{{ value_json['response'][0]['result'][0]['node4'] }}"
As I said before, I have no idea to validate the legitimacy right now, but since you specifically mentioned your unfamiliarity with home assistants JSON-parsing syntax it might give you enough info to implement it.
I additionally had custom switches to power on or off any nodes via home assistant, but I know that it didn't work the last time I tried it. I believe this was during testing the new version of the boards OS and I didn't had the time to invest fixing it at that time. As I remember, the changed some api calls, so maybe I just messed up some parameters to call the endpoints: configuration.yaml
Copy code
yaml
command_line: !include_dir_merge_list commands/
commands/turing_nodes_power_switch.yaml
Copy code
yaml
- switch:
    name: turing_pi_node_1_power
    command_on: "curl --insecure -u '<username>:<password>' -X POST 'https://<ip-address>/api/bmc?opt=power&type=set&node1=1'"
    command_off: "curl --insecure -u '<username>:<password>' -X POST 'https://<ip-address>/api/bmc?opt=power&type=set&node1=0'"
    command_state: "curl --insecure -u '<username>:<password>' -X GET 'https://<ip-address>/api/bmc?opt=power&type=get'"
    value_template: "{{ value_json['response'][0]['result'][0]['node1'] | int == 1 }}"
# Code would become to long for Discord, so just replace 'XXX' with the node index.
- switch:
    name: turing_pi_node_XXX_power
    command_on: "curl --insecure -u '<username>:<password>' -X POST 'https://<ip-address>/api/bmc?opt=power&type=set&nodeXXX=1'"
    command_off: "curl --insecure -u '<username>:<password>' -X POST 'https://<ip-address>/api/bmc?opt=power&type=set&nodeXXX=0'"
    command_state: "curl --insecure -u '<username>:<password>' -X GET 'https://<ip-address>/api/bmc?opt=power&type=get'"
    value_template: "{{ value_json['response'][0]['result'][0]['nodeXXX'] | int == 1 }}"
t
Thanks so much! I'll have a crack later this week but it looks like I wasn't correctly eliminating the two outer arrays in the value_template parts, and was getting confused by the apparently unneeded json_attributes_path item. HA's documentation is thorough, but it'd be awesome if they showed the sample json that the config files are responding to in their rest documentation.
I'm still figuring out this part. Using the BMC API for on makes a lot of sense, but I'm wondering if leaving a switch on the card for an SSH based shut down command to the nodes (and possibly a later power down in BMC on a time/ping based automation) would be better.
Sorry to hear your tpi is unreliable too 😕. I really appreciate the help.
b
The Turing Pi itself seems to work without problems, or at least the nodes are still running and accessable. I just can't find the Turing device on my network and am unable to connect to it via SSH or HTTP(S), which would mean restarting the entire cluster. The problem seems to be the services running on the Turing which fail at some point and have no way to restart. Just haven't figured out a fix for it, especially since I'm currently waiting for my second Turing Pi so I could work on one in peace and keep the other running.
t
The syntax worked perfectly for power state and I'm still working on the dashboard. I slightly edited to make the sensors binary, and applied the 'connectivity' device class so that "Connected/Not Connected" terminology matched the ping results on the same card (by default a binary sensor is On/Off).
Copy code
- resource: https://xx.xx.xx.xx/api/bmc?opt=get&type=power
  authentication: basic
  username: user
  password: pass
  verify_ssl: false
  binary_sensor:
    - name: tpi-power-node1
      value_template: "{{ value_json['response'][0]['result'][0]['node1'] }}"
      unique_id: tpi-p1
      device_class: connectivity
      icon: mdi:power
    - name: tpi-power-node2
      value_template: "{{ value_json['response'][0]['result'][0]['node2'] }}"
      unique_id: tpi-p2
      device_class: connectivity
      icon: mdi:power
I didn't end up using info sensors, as this was depreciated with the new version of the BMC API, but did create a custom sensor for USB state, which combines the three fields (node, mode, and whether USB port/BMC routed) into a single value:
Copy code
- resource: https://xx.xx.xx.xx/api/bmc?opt=get&type=usb
  authentication: basic
  username: user
  password: pass
  verify_ssl: false
  sensor:
    - name: tpi-usb-state
      value_template: "{{ (value_json['response'][0]['result'][0]['mode']) }} mode - {{ (value_json['response'][0]['result'][0]['node']) }} to {{ (value_json['response'][0]['result'][0]['route']) }}"
      unique_id: tpi-usb
      icon: mdi:usb
Still haven't decided exactly how to integrate power control yet into my cards. I'm tempted to make power off commands ssh-based calls to the individual nodes (to avoid dirty shutdowns), and possibly automate closing the power on the BMC if idle >10mins (this becomes a pseudo-watchdog) but worry it might fire inadvertently. I'm also grappling with whether to make the panel accessible to my partner for me-away troubleshooting, but there's possibly a need then to lock down certain things as you could end up with a non-operational state (eg. reverse proxy that most services rely on is powered off)
So I've got Home Assistant speaking nicely with the BMC now. It wasn't as straightforward as I hoped, as a command style switch wasn't reliably updating it's state based on the BMC. However in a slightly roundabout way I got it working with three entities per node. A) a binary rest sensor that provides on/off state of the node. B) A command-style switch which can send an on or off command for each node via a shell script. C) A template switch, that relies on the sensor to set states, and forwards any user On/Off requests to the command switch. Note this is only needed if you want a toggle style switch. If you're comfortable displaying state one one line of an entities card, and having separate on/off buttons on another row, you can skip step C.
A) Binary REST sensors /config/rest/turing_state.yaml:
Copy code
- resource: https://IP-OR-HOST/api/bmc?opt=get&type=power
  authentication: basic
  username: user
  password: pass
  verify_ssl: false
  binary_sensor:
    - name: tpi-power-node1
      value_template: "{{ value_json['response'][0]['result'][0]['node1'] }}"
      unique_id: tpi-p1
      device_class: connectivity
      icon: mdi:power
{.... and so on}
B) Command switch Note the core issue with @blaickgaming's template above seems to be the use of http POST requests, because the API confusingly uses GETs for set commands. I've tried dozens of different permutations of the command_state and value_template options, and not been able to find anything that reliably updates the switch state over time. Not including them here means that this switch entity has separate on/off buttons rather than a toggle. This entity is where HA attributes all on off activity for graphing/activity log purposes (rather than the Template switch below, or the binary sensor) /config/commands/turing_switches.yaml:
Copy code
- switch:
    name: tpi-node1
    command_on: "/config/commands/tpi-api.sh power_on node1"
    command_off: "/config/commands/tpi-api.sh power_off node1"
{...and so on}
I've also attached my shell script below: https://cdn.discordapp.com/attachments/1194509611139596318/1198935982075027498/tpi-api.sh?ex=65c0b725&is=65ae4225&hm=eeb8dffdefcb390ad863469f46156a02d92ee9911c62fc0cf46b0d1c575c4d5b&
C) Template Switch to tie it all together These are stored in /configuration/configuration.yaml because I couldn't be bothered troubleshooting a bigger config issue.
Copy code
switch:
  platform: template
  switches:
    tpi_ts_node1:
      friendly_name: "Turing Pi Node 1"
      value_template: "{{ is_state('binary_sensor.tpi_power_node1', 'on') }}"
      turn_on:
        - service: switch.turn_on
          target:
            entity_id: switch.tpi_node1
        - service: homeassistant.update_entity
          target:
            entity_id: binary_sensor.tpi_power_node1
      turn_off:
        - service: switch.turn_off
          target:
            entity_id: switch.tpi_node1
        - service: homeassistant.update_entity
          target:
            entity_id: binary_sensor.tpi_power_node1
{... and so on}
Note that the script I've attached here also implements most of the other state-changing API commands usb_boot, clear_usb_boot, network, node_to_msd, power_on, power_off, reboot and reload in case I need them in the future. Yes, I'm aware I reinvented the tpi binary in Bash 😕 but it was more suitable for my needs here. Due to bugs in how the API manages reset (my script couldn't handle node numbering in the original API's starts-at-zero-sometimes format) I haven't implemented it here, nor do I plan to try for the uart endpoint either.
Next steps are to get uptime and temperature integrated, but these will be via SSH calls as the API doesn't expose them.
b
Thank you for your hard work in creating a better integration for home assistant. From what I've read it looks very promising. Will definitely test it out on my system, when I receive the RK1 modules.
r
So youre using home assist to power on/off your TPI?
t
I'm using it to power individual nodes on and off - HA gives me a better interface for my needs, exposes it to the user access controls there, and doesn't expose the BMC API externally. I've scripted the ability to power off the BMC from HA, but won't use it myself because my HA server is on a node and I don't want to inadvertently take my entire home setup offline.
j
That’s awesome
I fully intend to run home assistant on the tpi so I will be grateful for your work once my board comes in
14 Views