Controlling a POE switch from Home Assistant

In my quest to save on electricity I detected my TV set was using quite some energy while “Sleeping”. It turned out it wasn’t sleeping the whole time, waking every x minutes trying to get to the internet (it’s not allowed to) for a few minutes and then going back to sleep.

The TV is connect to a little switch along with other audio/video equipment to the LAN. So to test what would happen if the TV was really disconnected from the network I turned the switch off. Turned out the TV became a bit more willing to sleep. It still wakes every hour or so to check if there is network available but that takes under a minute after which the TV falls asleep again.

As most of the things in my house are automated via Home Assistant, wouldn’t it be great if the switch is also automatically told to switch off (instead of me pulling the plug).

The switch is a Unify flex mini which is powered via an Edgeswitch. This switch can be managed via SSH, so this called for a script 🙂

I used Paramiko, a python ssh module, to write a small script and control the interface to which the POE switch is connected.

Note, the script has debug enabled: it outputs the ssh conversation. Set DEBUG to False to disable this behaviour.

from paramiko import SSHClient, AutoAddPolicy, Channel
import time
import sys

MAX_BUFFER = 65535
DEBUG = True

LOGON_HOST='<ip address switch>'
LOGON_USER='<admin user (default ubnt)>'
LOGON_PASSWORD='<admin user password>'
HOSTSFILE='/home/homeassistant/control_hosts'

#print on debug
def print_on_debug(line):
  if DEBUG:
    print(line.decode())

  return line

#send a command and return the output
def send_command(channel, cmd='', wait=1):
  cmd = cmd.strip()
  channel.send(cmd + '\n')
  time.sleep(wait)
  
  if channel.recv_ready():
    return print_on_debug(channel.recv(MAX_BUFFER))

#Flushes the receive buffer
def flush_buffer(channel):
  time.sleep(1)

  if channel.recv_ready():
    return print_on_debug(channel.recv(MAX_BUFFER))


#Initialize client object
def init_client(hostsFile, autoadd=True):
  client = SSHClient()
  client.load_host_keys(hostsFile)

  if autoadd:
    client.set_missing_host_key_policy(AutoAddPolicy())

  return client

#enter configuration mode
def enter_configure(channel):
  send_command(channel, 'enable')
  send_command(channel, LOGON_PASSWORD)
  send_command(channel, 'configure')
  
#Turn off poe on interface
def poweroff_poe(channel, interface):
  send_command(channel, 'interface '+interface)
  send_command(channel, 'poe opmode shutdown')
  send_command(channel, 'exit')

#Turn on poe on interface
def poweron_poe(channel, interface):
  send_command(channel, 'interface '+interface)
  send_command(channel, 'poe opmode auto')
  send_command(channel, 'exit')

def main(argv):
  command = argv[1]

  client = init_client(HOSTSFILE)
  client.connect(LOGON_HOST, username=LOGON_USER, password=LOGON_PASSWORD)
  channel = client.invoke_shell()

  if command == 'poweroff_interface':
    interfaceNo = argv[2]
    flush_buffer(channel)
    enter_configure(channel)
    poweroff_poe(channel, interfaceNo)

  elif command == 'poweron_interface':
    interfaceNo = argv[2]
    flush_buffer(channel)
    enter_configure(channel)
    poweron_poe(channel, interfaceNo)
  else:
    print('Unknown command')

  client.close()

if __name__ == '__main__':
  if len(sys.argv) < 3:
    print('Usage: {} command [options]'.format(sys.argv[0]))
  else:
    main(sys.argv)

The script is basically a very small ssh client. It will connect to the switch to which the “tv switch” is connected and either turns off POE on the interface or turns it on. I use a custom hosts file to store the host identification, note: this file needs to exists.

Integrating it into Home Assistant is easy, I’ve added a boolean input, two shell command (turn on and turn off) and the automations for it.

input_boolean:
  tvswitch:
    name: TV Switch enabled
    inital: on
    icon: mdi:switch

shell_command:
  tvswitch_poweroff: "python /home/homeassistant/scripts/switch_control.py poweroff_interface 0/5"
  tvswitch_poweron: "python /home/homeassistant/scripts/switch_control.py poweron_interface 0/5"

The switch is attached to interface 5
The boolean is used by two automations

- id: "TV Switch toggle on"
  alias: "TVSwitch on"
  trigger:
    - platform: state
      entity_id: input_boolean.tvswitch
      to: "on"
  action:
    - service: shell_command.tvswitch_poweron

- id: "TV Switch toggle off"
  alias: "TVSwitch off"
  trigger:
    - platform: state
      entity_id: input_boolean.tvswitch
      to: "off"
  action:
    - service: shell_command.tvswitch_poweroff

So an easy way to control (cut the power) to the POE switch 🙂