esphome

package module
v0.0.13 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 18, 2026 License: MIT Imports: 38 Imported by: 0

README

pmaas-plugin-esphome

A PMAAS plugin for ESPHome devices. It embeds an MQTT broker, so PMAAS stays a single executable: your ESP32s are configured in ESPHome YAML to connect to PMAAS, announce what they have, and publish their state. There is no custom firmware.

Status: phase 3. Thermometers, door position sensors, switches (relays and smart plugs, which can be turned on and off from PMAAS) and power monitoring work over either of two transports: the embedded MQTT broker, or the ESPHome native API, which stock firmware (Kauf plugs, Athom relays) speaks with no MQTT and no reflashing. There is an ESPHome status page. Finding native devices by mDNS, adopting them from the page, and TLS are not done yet (see Roadmap).

The MQTT transport has been verified on real hardware (below). The native API, switches and power monitoring have only been tested against simulated devices so far.

Verified on a real ESP32 running ESPHome 2026.8.0, with an SHT3x temperature and humidity sensor and a reed switch: the device connects and its entities are discovered; temperature and humidity reach the environment plugin and update as the sensor reports; the door sensor reports its position, announces each open and close, and goes offline and back online as the device does (see Troubleshooting for the one setting it needs).

What you get

ESPHome entity Becomes Seen by
sensor with device_class: temperature a wireless thermometer entity the environment plugin, which renders and tracks it like a bluetooth thermometer
sensor with device_class: humidity folded into the thermometer, if the device has exactly one temperature sensor the same
binary_sensor with device_class: garage_door, door or opening a door sensor (pmaas-spi/device: IDoorSensor) anything that subscribes to its events

| switch | a switch (pmaas-spi/device: ISwitch): on, off, or unknown, and a way to ask for either | anything that subscribes to its events, and the buttons on the status page | | sensor with device_class: power, voltage, current or energy | one power monitor per device (device.IPowerMonitor), carrying whichever of those the device has | the same |

Anything else a device announces is logged and ignored. A door sensor reports Open, Closed or Unknown, when it last changed, and whether the device is currently connected; it broadcasts a device.DoorPositionChangedEvent when the position changes.

Switches

A switch reports On, Off or Unknown (a switch that hasn't said yet isn't assumed to be off). Asking it to change, from the status page or through ISwitch.SetState, publishes to the switch's command topic and returns at once; the switch's state changes when the device reports it has, so a command that's ignored leaves it as it was. Asking is refused, with the reason, if the device is offline, didn't announce a command topic, or the broker isn't running.

PMAAS publishes commands itself, with no ACL in the way, so it only ever does so to the device's own topics: an entity whose announced command topic is outside the device's tree (<name>/...) is refused, so one device can't make PMAAS command another.

Guarding a switch

A switch on the page is one press of its icon from changing, which is what you want for a lamp and not for the plug a server rack is on. Each device, MQTT or native, can say how carefully its switches are guarded, with Control:

conf.AddNativeDevice(esphome.NativeDeviceConfig{
	Name: "kauf-plug-7aad7c", Address: "10.47.6.71", DisplayName: "Server Rack",
	Control: esphome.SwitchControl{Level: esphome.ControlPassword, Password: "a password"},
})
Level What a person at the page has to do What another plugin has to do
ControlOpen (the default) press the icon nothing
ControlConfirm press it, and say yes when asked nothing
ControlPassword press it, and type the password nothing
ControlReadOnly nothing helps: the switch shows its state and won't change nothing helps either
  • Confirm and password are for people. They apply to the icon on the page, and not when another plugin turns a switch on or off through its ISwitch, since an automation has nobody to ask. Read-only is for everyone: nothing can change the switch.
  • The server decides. The page asks, but what's allowed is checked on the server from what the request carries, so a request that skips the question is refused the same way. The password is never sent to the page, and is compared in constant time.
  • Wrong passwords are limited. Five wrong ones in a row lock all of the device's switches for 30 seconds, during which even the right password is refused; a right one starts the count again. Each wrong one is logged, without what was typed.
  • A mistake is read-only, never open. A device set to ControlPassword with no password, or with a level that doesn't exist, has its switches made read-only and the plugin says why when it starts.
  • The password is in the configuration in plain text, and the page sends what's typed over whatever connection it's served on, so serve the page over TLS if the network isn't entirely yours. The prompt is a dialog of its own, not the browser's, so that what's typed is masked.

A guarded switch shows a lock (read-only), a key (password) or a shield (confirm) beside its state.

Power monitors

A device's power, voltage, current and energy sensors become one entity, with a flag for each reading saying whether the device has reported it: a device with no voltage sensor has no voltage, which isn't zero volts. Readings are converted to watts, volts, amps and kilowatt-hours whatever unit the device uses (kW, mW, mV, mA, Wh and MWh are understood; a sensor with any other unit is ignored and logged). If a device has two sensors of one kind the first by object id is used. What energy counts from (the device's lifetime, or since midnight) is up to the device.

Alerting when a device goes offline

A device can raise an alert on the alert console while it is offline. It is off unless a device asks for it, with alert.WhenOffline from pmaas-spi/alert, on either kind of device:

conf.AddDevice(esphome.DeviceConfig{
	Name: "garagedoor1", Password: "...",
	OfflineAlert: alert.WhenOffline(5*time.Minute, alert.Always(alert.SeverityCritical)),
})

The first argument is how long the device has to have been offline (zero is as soon as it is noticed). The second says how severe the alert is, and may depend on the time of day (alert.ByTimeOfDay); with nil it is a warning. The alert clears when the device connects again. A device that has never connected counts as offline from when the plugin started. The alert is esphome / offline:<device name>, and is looked at on the clock's minute event as well as when the device connects or disconnects, so that it comes due without anything happening.

Bluetooth proxies

A device that runs ESPHome's Bluetooth proxy (bluetooth_proxy: with esp32_ble_tracker:, on an ESP32) is also a source of Bluetooth advertisements: the bluetooth plugin recognises Govee and Inkbird sensors from what it hears, from this and from any other source (pmaas-plugin-bluez for the local radio). Nothing is configured. A device is a source if it says it sends raw advertisements, which is all that ESPHome 2025.8 and later send, over the native API. It is registered as an entity of its own, " Bluetooth", with the connection's state, what the scanner is doing, and counts of what it has heard and forwarded. To keep one that runs the proxy out of it, set DisableBluetooth: true on its NativeDeviceConfig.

  • Nothing is sent to PMAAS until the bluetooth plugin asks. It broadcasts what it wants (bluetooth.InterestEvent); only then does PMAAS subscribe to the proxy, and it unsubscribes when nothing is wanted. It re-subscribes after every reconnection, and the minute event is when a lapsed interest is noticed.
  • The rest is dropped here. A proxy hears about twenty advertisements a second, most from phones and neighbours' devices that nobody wants. Each advertisement is decoded (bluetooth.ParseAdvertisingData) and checked against what is wanted on the connection's goroutine, and only the wanted ones are broadcast, so the rest never touch the plugin's goroutine. Repeats are dropped for each proxy separately, so two proxies that hear the same sensor both report it.
  • Scanning mode follows what is wanted. If anything needs scan responses (names live in them for some devices) the proxy is asked to scan actively, and otherwise passively. It is asked once, and a proxy that doesn't change is left alone. Interval and window are in the proxy's YAML and can't be changed from here: ESPHome's stock proxy package scans a small fraction of the time, and a button that advertises briefly can be missed.
  • Others using the proxy. The scanner's mode is one for all clients, so another client (Home Assistant) that wants a different mode will fight this one. Recent ESPHome firmware may also take only one subscription to advertisements at a time (the device's own log says "Only one API subscription is allowed at a time" when it refuses): a second PMAAS, say one running on a laptop, could then leave the other hearing nothing while its connection looks fine.
  • A proxy that goes quiet is noticed. A connected, subscribed proxy that sends no batch of advertisements at all for two minutes (a house is never that quiet) is subscribed to again, with a warning in the log; if it is still silent two minutes later the connection is ended and made again, with an error in the log. A scanner that reports itself failed is subscribed to again at once. Ended connections are logged at warning, with how long they lasted.
  • The proxy is a block of its own in the device's card, like a switch or a thermometer, and is counted in the status bar ("N Bluetooth proxies"): the scan mode, how many batches it has sent and when the last came, and how many advertisements it heard, forwarded and dropped since PMAAS started. It is a card of its own because a device is often more than a proxy (the garage door controller measures and senses too). So the card's "Last message" is about what else the device sends, not about advertisements, and for a device that is only a proxy it is left out. A proxy that is connected but has sent nothing for two minutes is flagged on its block. If the batch count stops rising while the proxy is connected, something is wrong with it, not with PMAAS.

The status page

The ESPHome entry in the menu opens a page like the other plugins': a status bar, then a card for each device.

  • The status bar shows whether the broker is running (and why not, if it should be, or that it isn't needed when every device is on the native API), where it listens, how many of the configured devices are connected, how many entities of each kind there are, and when a device last sent anything.
  • A device's card shows its name, how it's reached (MQTT or Native API), whether it's connected and since when, and what it said about itself: address, firmware, model, MAC. If a native API device can't be reached, the reason is on its card. Inside the card is everything of the device's that's tracked, each in a block of its own. A device that has nothing tracked yet, or has never connected, still has its card.
  • What's inside is ordered by kind and then by name. Switches come first, then power monitors, door sensors and thermometers, as set by the priorities in childorder.go: the higher the number the earlier, and a kind that isn't listed comes after all that are, so a new kind appears at the end until someone decides where it belongs. To move a kind up, raise its number; a negative one puts it below the unlisted.
  • A switch shows its state, and the toggle icon is the control: press it to ask for the other state. It's only a picture while the device is offline or can't be commanded. The state changes when the device reports it, so the page reloads a second after the request to show it. A thermometer shows its temperature and humidity, a door sensor its position and for how long, and a power monitor the readings the device has. What an offline device last said is shown dimmed.

How it works

  1. A device connects to the broker with its own username and password.
  2. It publishes a retained discovery config per entity (this is ESPHome's Home Assistant style MQTT discovery, on by default): homeassistant/<component>/<device>/<object>/config.
  3. It publishes state to the topics those configs name, and its birth/last-will messages.
  4. The plugin registers an entity per supported config, and turns state messages into PMAAS events.

The broker only lets a device use its own topics: it may publish and subscribe under <device>/, and publish its own discovery configs. It cannot read or write another device's topics. The one exception is ESPHome's own node discovery (esphome/discover, esphome/ping/<device>): those topics are shared by every ESPHome device, and a device left at its defaults uses them on every connect. The broker takes in what a device sends there and throws it away, so the device is satisfied but nothing is delivered or retained, and devices can't see each other through it. Set discover_ip: false on the device to stop it sending them. Connectivity comes from the broker's own view of the connection, so a device that drops off shows as offline as soon as its keepalive lapses, with its last known state kept.

Retained messages live only in the broker's memory, so after PMAAS restarts the broker is empty until devices reconnect and republish. ESPHome does: on every connect it publishes its birth message (<device>/status), the retained discovery configs, and the current state of every entity, so a restart of PMAAS repopulates everything within moments of the devices reconnecting. ESPHome also forwards its own log lines to <device>/debug, which is harmless but shows up when CaptureMessages is on.

Configuring the plugin

conf := esphome.NewPluginConfig()           // listens on :1883, discovery prefix "homeassistant"
conf.AddDevice(esphome.DeviceConfig{
	Name:        "garage-left",              // must match the device's ESPHome name
	Password:    "a long random password",
	DisplayName: "Left Garage",              // optional
})
coreConfig.AddPlugin(esphome.NewPlugin(conf), config.PluginConfig{})
  • Name is both the MQTT username the device connects with and the root of the topic tree it owns, so the device's topic_prefix must be left at ESPHome's default, which is its name. Names cannot contain /, +, #, $ or whitespace.
  • DisplayName is shown in front of each entity's own name ("Left Garage Door"). Without it the name the device announces for itself is used.
  • Devices not listed here are refused. A device listed twice, an invalid name, a missing password, or an address already in use stops the broker from starting; the plugin logs why and the rest of PMAAS runs.
  • CaptureMessages: true logs every message devices publish. Use it the first time you connect a new kind of device to see exactly what it sends.

The broker listens in plain text. Use it on a trusted LAN only, and give each device its own password.

Example ESPHome configuration

A garage door position detector (a reed switch on GPIO) with a temperature/humidity sensor:

esphome:
  name: garage-left            # the PMAAS device Name; also the default topic_prefix

esp32:
  board: esp32dev

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

logger:

# MQTT only, so there is deliberately no `api:` section: ESPHome reboots a device that has an `api:`
# section but no API client connected, unless that section sets `reboot_timeout: 0s`.
mqtt:
  broker: pmaas.local          # the machine running PMAAS
  port: 1883
  username: garage-left        # same as the name
  password: !secret mqtt_password
  # discovery is on by default and publishes to the "homeassistant" prefix, as the plugin expects.

  # Recommended. ESPHome's own node discovery (on by default) lets tools find a node's address over MQTT.
  # PMAAS doesn't use it, and the broker accepts and discards what a device sends for it, so leaving it on
  # works, but it's traffic that does nothing for you.
  discover_ip: false

binary_sensor:
  - platform: gpio
    name: "Door"
    device_class: garage_door
    pin:
      number: GPIO4
      mode: INPUT_PULLUP
      inverted: true           # wire the reed switch so ON means open
    filters:
      - delayed_on_off: 100ms  # debounce

sensor:
  - platform: dht
    pin: GPIO5
    model: DHT22
    temperature:
      name: "Temperature"
    humidity:
      name: "Humidity"
    update_interval: 60s

ON means open and OFF closed, as with Home Assistant's door sensors. If you flip the wiring the wrong way around, flip inverted: rather than changing anything in PMAAS.

The name you give each entity in ESPHome is shown after the device's name, so with DisplayName: "Left Garage" an entity named "Temperature" is shown as "Left Garage Temperature". Name the entities relative to the device ("Temperature", "Door"), the way ESPHome and Home Assistant expect, rather than repeating where they are.

Troubleshooting

A device connects and is immediately disconnected, over and over. The device's log shows transport_read(): EOF followed by a reconnect, and PMAAS shows nothing from it except its own debug log lines. Look in the PMAAS log for a line like this:

level=WARN msg="denying publish to a topic the device may not use (an MQTT 3.1.1 client that sent it at QoS 1 or 2 is disconnected)" device=garagedoor1 topic=homeassistant/sensor/other-name/temp/config

The broker refuses anything a device does outside its own topics. For a subscription, that just fails. But MQTT 3.1.1 has no way to refuse a publish, so for one sent at QoS 1 or 2 the broker disconnects the device, which reconnects and sends it again. (At QoS 0 the message is dropped quietly, so the device stays connected.) The log line names the topic:

  • Another topic under esphome/: ESPHome's node discovery is tolerated (see above), but nothing else in ESPHome's own namespace is. Look at what the device is configured to publish there.
  • Anything under homeassistant/ for a different name than the device's: the device is announcing itself under a different node name than the one it connects with. Its ESPHome name must be the name configured for it here, with no MAC suffix (name_add_mac_suffix: false, the default).
  • Anything else: the device's topic_prefix isn't its name. Leave it at the default.

A sensor connects but doesn't appear in PMAAS. Look for a line like this in the PMAAS log:

esphome: garagedoor1: ignoring unsupported binary_sensor "garage_door_position" (device_class ""): if it's a door, set device_class: garage_door (or door) on it in the device's YAML

PMAAS decides what an entity is from its device_class, which ESPHome only announces if the YAML sets one. A binary_sensor with no device_class could be a door, a motion sensor, or anything else, so it isn't tracked. Set device_class: garage_door (or door, or opening) on it, as in the example above. Likewise a sensor needs device_class: temperature or humidity. Anything else (lights, switches, and so on) is ignored for now, and logged the same way.

If the log shows nothing at all, check that the device is listed in the plugin's config, and that its username and password are right: a failed login is logged too, as rejecting device connection.

Wiring it into an assembly

import esphome "github.com/avanha/pmaas-plugin-esphome"

func addEsphome(coreConfig *config.Config) {
	conf := esphome.NewPluginConfig()
	conf.CaptureMessages = true // while setting up
	conf.AddDevice(esphome.DeviceConfig{Name: "garage-left", Password: "...", DisplayName: "Left Garage"})
	coreConfig.AddPlugin(esphome.NewPlugin(conf), config.PluginConfig{})
}

Roadmap

  1. Phase 1 (this): broker with per-device authentication and ACLs, discovery parsing, thermometers and door sensors, connectivity, tests.
  2. Phase 2 (done): the status page, door sensor renderer, switches (ISwitch, commands to the device's command_topic) and power monitoring.
  3. Phase 3 (done, apart from real hardware): the ESPHome native API as a second transport next to the MQTT broker, so stock firmware that has no MQTT (Kauf and Athom plugs and relays) works without reflashing, with Noise encryption and the entity mapping above shared by both transports.
  4. Next: finding native devices by mDNS (_esphomelib._tcp), listing them on the status page, and adopting one from the page, with what's adopted kept in the core's config store.
  5. Later: BLE advertisements, TLS (the ACME plugin's certificate), a Tasmota dialect for devices that can't run ESPHome, signal strength as RSSI.

Devices on the native API

A stock Kauf plug or Athom relay has the native API on port 6053 and no MQTT. PMAAS connects to it, so there's nothing on the device to set up: tell PMAAS where it is.

conf := esphome.NewPluginConfig()
conf.AddNativeDevice(esphome.NativeDeviceConfig{
	Name:        "kauf-plug-1",  // the device's ESPHome name; refused if the device at Address says something else
	Address:     "10.0.0.7",     // or "plug1.local"; the port defaults to 6053
	DisplayName: "Space Heater", // optional
	// Key: "...",               // the device's api: encryption: key, if it has one
})

A device on both lists is an error. With only native devices configured the broker isn't started, and the page says so. Each device is its own connection: one that can't be reached, or has the wrong key, is shown on the page with what's wrong, and retried with a growing delay (a minute at most) without affecting the others. A device that reboots is reconnected and asked again for everything it has, so entities it no longer has are dropped.

PMAAS asks each device who it is, what entities it has, and to report their states, then maps the entities exactly as it does for MQTT: switch entities, sensor entities with a device_class of temperature, humidity, power, voltage, current or energy, and binary_sensor entities with a device_class of garage_door, door or opening. Anything else is logged and ignored. Turning a switch on or off sends the device a command, and the switch's state changes when the device reports it.

Not every device sends each entity's object id, which is what the plugin keys things by: a Kauf plug on ESPHome 2025.8.2 sent none for its sensors. When there isn't one it's worked out from the entity's name the way ESPHome does (Total Daily Energy is total_daily_energy), so the entity is the same either way, and two entities that would end up with the same one have their key put on the end, so readings can never land on the wrong sensor.

Security. Stock Kauf and Athom firmware runs the native API unencrypted, with no password, so anyone on the network can read it and command the device. Keep such devices on a network you trust (an IoT VLAN), or put an api: encryption: key: in their firmware and give PMAAS the key. Encryption is Noise (Noise_NNpsk0_25519_ChaChaPoly_SHA256) with that 32 byte key. If the wrong key, or none, is configured the page says which.

How the client works

internal/nativeapi is the client. It connects, does the encryption handshake if there's a key and the API hello, and delivers every message to a handler, answering pings and time requests itself, with a keepalive that gives up on a device that has gone quiet. A message it doesn't recognise is skipped rather than ending the connection, since a device on newer firmware than this was generated from is normal.

The protobuf bindings (internal/nativeapi/pb) are generated from ESPHome's api.proto as vendored by Home Assistant's client library, which is MIT licensed, pinned to the tag in internal/nativeapi/proto/SOURCE. To update them, replace the two .proto files with a newer tag's and run internal/nativeapi/generate.sh, which needs only Go. There was no Go client worth depending on: the maintained candidate ends the connection on a message type it doesn't know and doesn't check the device's reason for refusing a key.

It's tested against a fake device written from the protocol, in both framings. The encrypted side has not yet been tried against real firmware or Home Assistant's own client (that library couldn't be installed where this was written), so a first connection to a device with an api: encryption: key is the real test of it.

Not supported, on purpose

  • Home Assistant value_template (Jinja). An entity that needs one is skipped with a log line. ESPHome publishes plain values and doesn't need one.
  • More than one temperature sensor sharing a humidity sensor on one device: with several temperature sensors there is no telling which humidity sensor belongs to which, so none is attached.
  • ESPHome's native API. Only MQTT is used.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ControlLevel added in v0.0.7

type ControlLevel int

ControlLevel is how carefully a device's switches are guarded against being turned on or off by mistake. A switch on the status page is one press of its icon away from changing, which is what you want for a lamp and not for the plug a server rack is on.

const (
	// ControlOpen is the default: a press of the switch's icon sends the command.
	ControlOpen ControlLevel = iota

	// ControlConfirm has the page ask "Are you sure?" before it sends the command.
	ControlConfirm

	// ControlPassword has the page ask for a password, which the server checks against SwitchControl.Password
	// before it sends the command. Several wrong ones in a row lock the device's switches for a short while.
	ControlPassword

	// ControlReadOnly shows a switch but never changes it: not from the page, and not when another plugin asks.
	ControlReadOnly
)

func (ControlLevel) String added in v0.0.7

func (l ControlLevel) String() string

type DeviceConfig

type DeviceConfig struct {
	// Name is the device's ESPHome name. It's the MQTT username the device must connect with
	// (the "username" under "mqtt:" in its YAML) and the root of the topic tree it may use, so its
	// "topic_prefix" must be left at its default, which is this same name.
	Name string

	// Password is the MQTT password the device must connect with.
	Password string

	// DisplayName is the name to show for the device. If empty, the name the device announces for
	// itself is used, falling back to Name.
	DisplayName string

	// Control is how carefully the device's switches are guarded. The default is ControlOpen.
	Control SwitchControl

	// OfflineAlert raises an alert while the device is offline, if it is set with alert.WhenOffline: after how long, and
	// how severe. The default is no alert.
	OfflineAlert alert.OfflineAlert
}

DeviceConfig is one ESPHome device allowed to connect to the plugin's broker.

type DeviceHandle added in v0.0.9

type DeviceHandle struct {
	// contains filtered or unexported fields
}

DeviceHandle is the assembly's handle on a device it configured, for using the device's entities from the assembly. It's what AddDevice and AddNativeDevice return, and it's usable at once: a device only has entities once it has connected and announced them, so what's taken from the handle doesn't need the device to be there yet. A call made before then, or while the device is gone, fails; it doesn't wait.

kp4 := conf.AddNativeDevice(esphome.NativeDeviceConfig{Name: "kauf-plug-7981c8", Address: "10.47.6.74"})
plug := kp4.Switch("") // a device.ISwitch, to give to whatever turns it on and off

func (*DeviceHandle) Door added in v0.0.9

func (h *DeviceHandle) Door(name string) device.IDoorSensor

Door is one of the device's door sensors, by its name as shown on the page, or the device's only door sensor if name is empty. Which one is worked out at each call, from what the device has announced by then, so it works from the moment the device has connected and announced it, and the same one keeps working if the device goes away and comes back. Until then it answers as a sensor that has not reported anything.

func (*DeviceHandle) Name added in v0.0.9

func (h *DeviceHandle) Name() string

Name is the device's ESPHome name.

func (*DeviceHandle) Switch added in v0.0.9

func (h *DeviceHandle) Switch(name string) device.ISwitch

Switch is one of the device's switches, by its name as shown on the page, or the device's only switch if name is empty. Which one is worked out at each call, from what the device has announced by then.

Turning it on or off skips the confirmation and the password: those are for a person at the page. The device's ControlReadOnly is not skipped.

type NativeDeviceConfig added in v0.0.5

type NativeDeviceConfig struct {
	// Name is the device's ESPHome name. PMAAS checks that the device it reaches at Address says this, so
	// an address that has been handed to a different device is refused rather than trusted.
	Name string

	// Address is the device's host name or IP address, and optionally a port: "plug1.local",
	// "10.0.0.7:6053". The port defaults to 6053.
	Address string

	// Key is the device's api: encryption: key, if it has one: 32 bytes, base64 encoded, as it appears in the
	// device's YAML. Leave it empty for a device that isn't encrypted, which includes stock Kauf and Athom
	// firmware.
	Key string

	// DisplayName is the name to show for the device. If empty, the name the device calls itself is used.
	DisplayName string

	// Control is how carefully the device's switches are guarded. The default is ControlOpen.
	Control SwitchControl

	// OfflineAlert raises an alert while the device is offline, if it is set with alert.WhenOffline: after how long, and
	// how severe. The default is no alert. A device that has never connected counts as offline from when the plugin
	// started.
	OfflineAlert alert.OfflineAlert

	// DisableBluetooth is that the device is not to be used as a source of Bluetooth advertisements, though it runs
	// ESPHome's Bluetooth proxy. A device is a source if it says it is one, and the bluetooth plugin asks for what it hears.
	DisableBluetooth bool
}

NativeDeviceConfig is one ESPHome device that PMAAS connects to over the native API, which is what stock firmware (a Kauf plug, an Athom relay) has enabled, unlike MQTT. The device is the server, so PMAAS is told where it is, and nothing on the device needs configuring.

type Plugin

type Plugin interface {
	spi.IPMAASPlugin
}

func NewPlugin

func NewPlugin(config PluginConfig) Plugin

type PluginConfig

type PluginConfig struct {
	// ListenAddress is the address the embedded MQTT broker listens on. Defaults to ":1883".
	ListenAddress string

	// DiscoveryPrefix is the MQTT discovery topic prefix devices publish their entity configs
	// under. Defaults to "homeassistant", which is ESPHome's default.
	DiscoveryPrefix string

	// Devices lists the devices allowed to connect to the MQTT broker. A connection from anything else is
	// refused. If there are none, the broker isn't started.
	Devices []DeviceConfig

	// NativeDevices lists the devices PMAAS connects to over the native API.
	NativeDevices []NativeDeviceConfig

	// CaptureMessages logs every message a device publishes. It's for working out what a new kind
	// of device actually sends; leave it off otherwise.
	CaptureMessages bool
	// contains filtered or unexported fields
}

PluginConfig configures the plugin.

func NewPluginConfig

func NewPluginConfig() PluginConfig

func (*PluginConfig) AddDevice

func (c *PluginConfig) AddDevice(device DeviceConfig) *DeviceHandle

AddDevice allows a device to connect. The handle it returns is for getting at the device's entities from the assembly, and can be ignored.

func (*PluginConfig) AddNativeDevice added in v0.0.5

func (c *PluginConfig) AddNativeDevice(device NativeDeviceConfig) *DeviceHandle

AddNativeDevice adds a device to connect to over the native API. The handle it returns is for getting at the device's entities from the assembly, and can be ignored.

type SwitchControl added in v0.0.7

type SwitchControl struct {
	Level ControlLevel

	// Password is what ControlPassword asks for. A device set to ControlPassword with none is treated as read-only,
	// rather than as open: a mistake in the configuration mustn't unguard a switch.
	Password string
}

SwitchControl is how a device's switches are guarded. Confirming and the password are for a person pressing a switch on the page. They don't apply when another plugin turns a switch on or off, which has nobody to ask, but ControlReadOnly does: nothing can change a read-only switch.

The password is checked by the server and is never sent to the page, but it is in the configuration in plain text, and the page sends what's typed over whatever connection it's served on, so serve it over TLS.

Directories

Path Synopsis
Package data holds what the plugin's status page shows: a plain description of the plugin, its devices and its entities, built on the plugin's goroutine and then handed to the page's templates.
Package data holds what the plugin's status page shows: a plain description of the plugin, its devices and its entities, built on the plugin's goroutine and then handed to the page's templates.
internal
broker
Package broker embeds an MQTT broker (mochi-mqtt) with per-device authentication and topic ACLs, and reports what devices publish and when they connect or disconnect.
Package broker embeds an MQTT broker (mochi-mqtt) with per-device authentication and topic ACLs, and reports what devices publish and when they connect or disconnect.
entities
Package entities holds the entities this plugin registers with the container, and the stubs it hands out for them.
Package entities holds the entities this plugin registers with the container, and the stubs it hands out for them.
hadiscovery
Package hadiscovery parses the subset of Home Assistant style MQTT discovery that ESPHome (and Tasmota) publish to describe their entities: a retained JSON config per entity at <discovery_prefix>/<component>/[<node_id>/]<object_id>/config, with an empty payload meaning the entity was removed.
Package hadiscovery parses the subset of Home Assistant style MQTT discovery that ESPHome (and Tasmota) publish to describe their entities: a retained JSON config per entity at <discovery_prefix>/<component>/[<node_id>/]<object_id>/config, with an empty payload meaning the entity was removed.
nativeapi
Package nativeapi is a client for the ESPHome native API: the protocol ESPHome devices speak on TCP port 6053, which Home Assistant uses to talk to them.
Package nativeapi is a client for the ESPHome native API: the protocol ESPHome devices speak on TCP port 6053, which Home Assistant uses to talk to them.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL