PHAL

March 12, 2026 · View on GitHub

Entry point group: opm.phal Admin entry point group: opm.phal.admin Template: ovos_plugin_manager.templates.phal

PHAL plugins are daemon threads that integrate OVOS with platform-specific hardware (LEDs, fans, buttons, display panels, etc.). They receive bus events and can emit their own bus messages.


PHALPlugin base class

from ovos_plugin_manager.templates.phal import PHALPlugin

Extends threading.Thread with daemon=True.

Constructor

PHALPlugin(bus=None, name: str = "", config: Optional[dict] = None)

On init the plugin automatically:

  1. Reads config from Configuration()['PHAL'][name] (or uses config if provided).
  2. Registers all core bus event handlers (audio, enclosure, eyes, mouth).
  3. Calls start() to begin the daemon thread.
AttributeTypeDescription
busMessageBusClientOVOS message bus connection.
namestrPlugin identifier (used in bus event namespacing).
configdictPlugin-specific configuration.
logLoggerLogger instance.

Lifecycle

run()

Override to implement the plugin's main loop. Called automatically after start().

shutdown()

Unregister all bus event handlers and stop the daemon thread. Called by OVOS on service shutdown.

Bus event handlers (all optional to override)

All handlers receive a Message argument.

Audio events

HandlerBus message
on_record_beginrecognizer_loop:record_begin
on_record_endrecognizer_loop:record_end
on_audio_output_startrecognizer_loop:audio_output_start
on_audio_output_endrecognizer_loop:audio_output_end
on_awakemycroft.awoken
on_sleeprecognizer_loop:sleep
on_speakspeak

System events

HandlerBus message
on_resetenclosure.reset
on_no_internetenclosure.notify.no_internet
on_system_resetenclosure.system.reset
on_system_muteenclosure.system.mute
on_system_unmuteenclosure.system.unmute
on_system_blinkenclosure.system.blink

Eye events

HandlerBus message
on_eyes_onenclosure.eyes.on
on_eyes_offenclosure.eyes.off
on_eyes_blinkenclosure.eyes.blink
on_eyes_narrowenclosure.eyes.narrow
on_eyes_lookenclosure.eyes.look
on_eyes_colorenclosure.eyes.color
on_eyes_brightnessenclosure.eyes.level
on_eyes_volumeenclosure.eyes.volume
on_eyes_spinenclosure.eyes.spin
on_eyes_timed_spinenclosure.eyes.timedspin
on_eyes_resetenclosure.eyes.reset
on_eyes_set_pixelenclosure.eyes.setpixel
on_eyes_fillenclosure.eyes.fill

Mouth / display events

HandlerBus message
on_display_resetenclosure.mouth.reset
on_talkenclosure.mouth.talk
on_thinkenclosure.mouth.think
on_listenenclosure.mouth.listen
on_smileenclosure.mouth.smile
on_visemeenclosure.mouth.viseme
on_viseme_listenclosure.mouth.viseme_list
on_textenclosure.mouth.text
on_displayenclosure.mouth.display
on_weather_displayenclosure.weather.display

Helper methods

emit(msg_type: str, msg_data: Optional[dict] = None)

Emit a bus message scoped to this plugin: ovos.PHAL.<name>.<msg_type>.

mouth_events_active: bool (property)

Whether mouth/viseme events are currently enabled.


PHALValidator

from ovos_plugin_manager.templates.phal import PHALValidator

Called before a PHAL plugin is loaded. Return False to prevent loading (e.g. on unsupported hardware).

class PHALValidator:
    @staticmethod
    def validate(config: dict = None) -> bool:
        ...

Assign your validator class to PHALPlugin.validator:

class MyPHALPlugin(PHALPlugin):
    validator = MyPHALValidator

The default validator returns True unless config['enabled'] is explicitly False.


AdminPlugin / AdminValidator

Identical to PHALPlugin / PHALValidator but registered under the opm.phal.admin entry point. Admin plugins may run with elevated privileges.


Configuration

{
  "PHAL": {
    "my-phal-plugin": {
      "enabled": true,
      "some_setting": "value"
    }
  }
}

The enabled key is checked by the default PHALValidator. Set to false to disable a plugin without uninstalling it.