Supported Types of Device Control#

Examples#

This project has been tested against several power control devices. These specific examples have their own documentation pages as follows:

Kasa Device Control#

example:

TP-Link Kasa Smart Plug

Kasa devices are controlled using the Python-Kasa library which interfaces with TP-Link Kasa smart devices over the network. This method involves asynchronous communication with devices to execute actions like turning on or off and querying their current state.

An example configuration for controlling a Kasa smart plug is shown below:

example yaml:

- type: KasaDevice
    name: server01_plug
    ip_address: 192.168.1.100
    on: "python -m kasa --host 192.168.1.100 on"
    off: "python -m kasa --host 192.168.1.100 off"
    query: "python -m kasa --host 192.168.1.100 state"

This configuration uses the Python-Kasa API to communicate with the plug. The ‘ip_address’ should be replaced with the IP address of your Kasa device. The ‘on’, ‘off’, and ‘query’ commands are examples of how you might invoke device control through command line interfacing with the Python-Kasa library.

Note

Ensure that the ‘python-kasa’ library is installed in the environment where your server is running, as it is required for communication with Kasa devices.

Command Line Control#

example:

TP Link Tapo Smart Plug

The simplest form of control is to execute a command line utility. Clearly the command tool needs to be installed on the machine running the webhook server, the server account needs permission to run it and the tool must be able to contact the device from the server.

A common example for RPI power is a switchable USB hub. Most of these can be controlled by the uhubctl command line tool. (see mvp/uhubctl).

Using uhubctl implies that the hub in question is plugged into a USB port on the webhook server.

example yaml:

- type: CommandLine
    name: pi2
    on: uhubctl -a 1 -p 2
    off: uhubctl -a 0 -p 2
    query: uhubctl -p 2
    query_on_regex: .*power$
    query_off_regex: .*off$

SmartThings Control#

example:

TP Link Tapo Smart Plug

SmartThings are IoT devices which are controlled using a SmartThing api token and SmartThing device ID. Once you have set up a SmartThing and tested it via the associated App you will be able to discover your device ID via the App. You can get your api token by logging in here: https://account.smartthings.com/login.

Note that the ip_address of 0.0.0.0 tells the server to listen on all interfaces on the machine on which it is running. Instead one could supply the IP of a single NIC or for best security use 127.0.0.1, meaning that only processes on the same machine will have access (in this cases you would run the webhook server on the maas rack server).

SmartThing commands for switch devices will usually take the exact same form as in the above example. Command line devices will just take a command line to execute in the shell.

In all cases the response from the query command is passed through a regex search and will return ‘on’ if the the response matches query_on_regex and ‘off’ it matches query_off_regex. Note that the defaults for these regex are ‘on’ and ‘off’ which is what SmartThing devices will return in the switch status field by default. This is why the nuc1 example is not required to specify query_on_regex, query_off_regex.

Note that the query response which goes to MAAS is converted to MAAS default values and hence no configuration of regex in MAAS itself are required.

example yaml:

- type: SmartThingDevice
    name: nuc1
    # token and id redacted
    api_token: YOUR_SMART_THINGS_API_TOKEN
    device_id: YOUR_SMART_THING_DEVICE_ID
    off: main switch off
    on: main switch on
    query: switch

Web GUI Control#

example:

Netgear GS803EP PoE 8 port switch

For those power control devices that are configured by a web UI only, I provide a Web Scraping device type. This uses the python selenium library to click buttons and send text to forms on any Web UI. Defining the correct sequence should allow you to login to any Web GUI and control it.

Per Control Device Configuration#

For this device type there are two types of entry. First is the global entry where you configure how to connect/disconnect to/from each device. (i.e. if you had 2 PoE switches you would have 2 of these)

example WebGui yaml:

- type: WebGui
    name: GS308EP
    connect_url: http://GS308EP_IP_ADDRESS
    timeout: 10
    driver: /home/giles/work/maaspower/utils/chromedriver
    login: |
        sendcr/cls/pwd-field-text/PASSWORD_GOES_HERE
        click/link/POE
    logout: |
        click/cls/src-views-header-nav-icon-button
        click/cls/icon-logout
        click/id/modal_footer_button_primary

You will need the chromedriver for selenium for this to work. Download from here (pick one that matches your Chrome version):

The configuration ‘driver:’ needs to point at the downloaded file. ‘timeout:’ should be the max time taken for any transitions in the click sequences you specify.

‘login:’ and ‘logout’: specify the sequence of clicks to perform these two tasks.

The configuration strings are ‘/’ separated fields as follows:

Commands#

:click/…

clicks on the specified HTML Element

send/…/text_to_send

sends text to a specified HTML Element

sendcr/…/text_to_send

sends text plus carriage return to a specified HTML Element

get/…

gets the text from a specified HTML Element

delay/n

pauses for n seconds (floating point supported)

Field Identifiers#

The second and third parts of the / separated strings identify the HTML Element to target:

n/value

finds the fields whose name is ‘value’

cls/value

finds the fields whose class is ‘value’

link/value

find the fields with link contents specified by a partial match on ‘value’

id/value

find the fields whose id is ‘value’

NOTE: in all cases if more than one field is matched you can index it like this:

command/match_type/value[n]

Where n is the 0 based index into the list of fields.

NOTE: in all cases the code will wait for the specified field to be seen if it cannot immediately be seen. ‘timeout’ specifies the maximum wait time before an error.

When the web scraper detects an error it will execute the logout script (ignoring errors) followed by the login script and try again. This has been shown to successfully recover on the GS308EP when it has timed out due to inactivity and gone back to the login screen.

Per Control Device Configuration#

For each computer that you want to power control you will need an additional entry like the following example. On, Off and Query use the same syntax as described above.

Note that the name has the entry above’s name followed by a computer name separated by ‘-’ this is important as it associates this entry with the correct Web Device. Only one instance of the selenium driver is loaded per web device and can control any number of target PCs.

The _regex parameters are regular expressions which will try to match the text returned from the final get in the query sequence. If there is a match it will return on or off to MAAS, or an error if there is none.

example WebDevice yaml:

- type: WebDevice
    name: GS308EP-pi5
    on: |
        click/n/isShowPot3
        click/n/editPot3
        click/cls/poePortPwrTxt
        click/link/Enable
        click/n/submitPotedit
    off: |
        click/n/isShowPot3
        click/n/editPot3
        click/cls/poePortPwrTxt
        click/link/Disable
        click/n/submitPotedit
    query: |
        delay/5
        get/cls/portPwr[2]
    query_on_regex: Enable
    query_off_regex: Disable

Working with another Web GUI#

This has been tested with the Netgear GS3008EP. I have tried to make a generic DSL that allows for most possible sequences of Web Element interactions, but YMMV.

To experiment with the approach and develop your own command sequences for this device type see the python script here: gilesknap/maaspower You can launch this script interactively with iPython and experiment with your device to get the right sequence of commands to turn devices on/off and query their state. See the comments in the file for details.

If you are brave enough to create your own config for a new device, please report any problems here gilesknap/maaspower#issues. Also post any working configurations too (you can do a PR to the docs or report in issues).

Cisco IOS PoE Switch Device Control#

example:

Cisco IOS PoE Switches

Warning

This module has been developed against and only tested on a Cisco Catalyst 2960X (WS-C2960X-24PS-L) with IOS version 15.2(7)E4.

Cisco IOS PoE switches are controlled using the netmiko library, which interfaces with the switch using ssh. This method will manipulate the power inline configuration option on a switch port interface to turn a connected PoE device on or off.

A YAML configuration example for controlling a Raspberry Pi 4B (PoE powered) is shown below:

- type: CiscoIOSPOESwitch
  name: rpi_4b_1
  ip_address: 10.0.0.1
  username: "root"
  password: "123qwe"
  port_selection_string: "gigabitEthernet 1/0/22"

  # Optional parameters
  #enable_password: "123qwe"
  #port_poe_watts: 30

The above example pertains to a Raspberry Pi 4B, labeled ‘rpi_4b_1’’ (with PoE HAT), connected to a Cisco Catalyst 2960X PoE switch at switchport ‘gigabitEthernet 1/0/22’. The Cisco switch hosts SSH accessible at IP ‘10.0.0.1’. Maaspower will establish an SSH connection to the switch utilizing the credentials ‘root’/’123qwe’. No specific PoE budget is necessary, hence the port_poe_watts parameter remains unset. Given the privileged status of the root user account, no enablement is required, rendering the enable_password unset.

Parameter

Required

Description

type

Y

Class/type of device controlling the endpoint device

name

Y

Logical device name for server connected to the Cisco switch port

ip_address

Y

IP address of the Cisco IOS PoE switch

username

Y

Username for the Cisco IOS PoE switch

password

Y

Password for the Cisco IOS PoE switch

port_selection_string

Y

Port selection for the target device connected to the switch in Cisco format

enable_password

N

Enable/secret password for escalating privileges on the Cisco switch

port_poe_watts

N

Power budget (in watts) for the target Cisco switch port