bitbee/php-dashboard-module-device-manager

IoT device management module for php-modular-dashboard: logging, automation, and dashboard for home automation

Maintainers

Package info

github.com/yoodoohai/php-dashboard-module-device-manager

Homepage

Issues

pkg:composer/bitbee/php-dashboard-module-device-manager

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

dev-main 2026-01-24 21:31 UTC

This package is auto-updated.

Last update: 2026-03-24 22:05:19 UTC


README

A standalone PHP package for managing smart home devices with support for data collection, control commands, and solar-excess-based automation. Originally designed for solar power systems, it can be used with any devices that support HTTP APIs.

Features

  • 🔌 Multi-Device Support - Manage Solax inverters, Go-E wallboxes, Shelly switches, Fröling heating systems, Midea ACs
  • Solar Automation - Automatic load shifting based on excess solar power and battery state
  • 📊 Data Collection - Periodic device polling with JSON logging
  • 🎮 Control Interface - Send commands to devices via HTTP APIs
  • 🔒 Permission System - Granular device-level access control
  • 🌍 Multi-language - Device labels and UI text in English and German
  • 📝 Command Logging - Full audit trail of all device commands

Requirements

  • PHP 8.0 or higher
  • cURL extension (recommended) or allow_url_fopen
  • Network access to devices

Installation

As Part of Dashboard

The device_manager is pre-installed in the modules/ directory of the main dashboard. No additional installation needed.

Standalone Usage

# Copy the device_manager folder to your project
cp -r device_manager /path/to/your/project/

# Include bootstrap and use
require_once 'device_manager/bootstrap.php';
require_once 'device_manager/src/DeviceManager.php';

$manager = new \Devicemanager\DeviceManager();

Standalone logging

When running standalone, logs default to device_manager/logs/.

You can override the log directory by setting either:

  • DEVICE_MANAGER_LOG_BASE=/absolute/path/to/logs
  • LOG_BASE_PATH=/absolute/path/to/logs

Standalone automation (CLI)

# optional: force standalone mode even if embedded
DEVICE_MANAGER_STANDALONE=1 php automate.php

Standalone setup UI (web)

You can run the setup UI without the main dashboard:

cd device_manager
DEVICE_MANAGER_LOG_BASE="$(pwd)/logs" php -S 127.0.0.1:8089 -t public

Then open http://127.0.0.1:8089/setup.php in your browser.

Setup UI (Dashboard + Standalone)

  • Dashboard module: ?module=DeviceSetup&method=edit&id=<deviceId>
  • Standalone setup page (within the module directory): public/setup.php

Both UIs use the shared helpers in src/SetupHelper.php and store configuration in config/devices.registry.json.

Quick Start

1. Configure Devices

Copy the example registry:

cp config/devices.registry.example.json config/devices.registry.json

Edit config/devices.registry.json to add your devices:

{
  "devices": [
    {
      "id": "my_device",
      "type": "http_switch",
      "name": "My Smart Switch",
      "host": "192.168.1.100",
      "enabled": true
    }
  ]
}

2. Collect Data

require_once 'bootstrap.php';
require_once 'src/DeviceManager.php';

$manager = new \Devicemanager\DeviceManager();

// Collect from single device
$data = $manager->collect('my_device');

// Collect from all enabled devices
$errors = $manager->collectAllDevices(true); // true = CLI output

3. Control Devices

// Send a control command
$result = $manager->control('my_device', 'power', 'on');

if ($result['success']) {
    echo "Device turned on!";
}

4. Run Automation (CLI)

php automate.php

Supported Device Types

Type Class Description
solax SolaxDevice Solax hybrid inverters via Modbus TCP
goe_charger GoeChargerDevice Go-E Charger wallboxes (API v2)
http_switch HttpSwitchDevice Generic HTTP-controlled relays (Shelly, etc.)
froeling FroelingDevice Fröling heating systems via cloud API
midea_ac MideaACDevice Midea air conditioners via local control

Device Configuration

Common Fields

Field Type Description
id string Unique device identifier
type string Device type (see table above)
name string Human-readable name
host string Device IP or hostname
enabled boolean Enable/disable device
role string producer, consumer, heating, cooling
logging object Log file settings
automation object Automation configuration
capabilities object Data points and metadata

Example: Shelly Switch

{
  "id": "shelly_heater",
  "type": "http_switch",
  "name": "Water Heater",
  "enabled": true,
  "role": "consumer",
  "collector": {
    "host": "192.168.1.50",
    "url": "http://{host}/status",
    "method": "GET",
    "mapping": {
      "status_key": ["relays", 0, "ison"],
      "power_key": {"path": ["meters", 0, "power"]}
    }
  },
  "actions": {
    "power": {
      "values": {
        "On": {"url": "http://{host}/relay/0?turn=on", "color": "#4CAF50"},
        "Off": {"url": "http://{host}/relay/0?turn=off", "color": "#9E9E9E"}
      }
    }
  },
  "automation": {
    "enabled": true,
    "min_watt": 2000,
    "turn_on_action": "power",
    "turn_on_value": "On",
    "turn_off_action": "power",
    "turn_off_value": "Off"
  }
}

Example: Go-E Wallbox

{
  "id": "wallbox",
  "type": "goe_charger",
  "name": "Garage Wallbox",
  "host": "192.168.1.60",
  "enabled": true,
  "role": "consumer",
  "state_file": "wallbox_state.json",
  "automation": {
    "enabled": true,
    "battery_discharge_policy": true,
    "zoe_mode": true
  }
}

Automation System

The automation system allocates excess solar power to consuming devices based on priority.

Configuration

{
  "settings": {
    "automation": {
      "power_source_device_id": "solax_main",
      "surplus_mode": "export_plus_divertable_battery",
      "battery_min_soc_start": 20,
      "battery_start_hour": 6,
      "battery_threshold": 90,
      "battery_target_hour": 13,
      "reserve_power": 100,
      "min_power": 300
    }
  }
}
Setting Description
power_source_device_id Device ID used as system power source (must provide grid_power, battery_power, battery_soc in raw data, or "Grid W"/"Batt W"/"Batt %" in formatted logs)
surplus_mode export_only or export_plus_divertable_battery
battery_min_soc_start SOC (%) threshold at battery_start_hour
battery_start_hour Start hour for dynamic SOC ramp
battery_threshold Target SOC (%) by battery_target_hour
battery_target_hour Target hour for dynamic SOC ramp
reserve_power Power (W) to always keep available
min_power Minimum excess before enabling any device

Device Automation Options

{
  "automation": {
    "enabled": true,
    "priority": 10,
    "min_watt": 1500,
    "turn_on_action": "power",
    "turn_on_value": "On",
    "turn_off_action": "power",
    "turn_off_value": "Off",
    "manual_override_permission": "device.my_device.automate"
  }
}

Devices with lower priority numbers are powered first.

Logging

Device Logs

Each device writes to its configured log file in JSON format:

{
  "timestamp": "2026-01-13 10:30:00",
  "status": "on",
  "power": 2500,
  "energy": 123.45
}

Command Log

All control commands are logged to automation.commands.json:

{
  "timestamp": "2026-01-13 10:30:00",
  "device_id": "shelly_heater",
  "action": "power",
  "value": "On",
  "success": true,
  "context": {"source": "automation"}
}

Automation Log

Each automation run is logged to automation.json:

{
  "timestamp": "2026-01-13 10:30:00",
  "excess_power": 3500,
  "battery_soc": 85,
  "available_power": 3000,
  "executed_actions": {...}
}

API Reference

DeviceManager

// Initialize
$manager = new DeviceManager(?string $registryPath = null);

// Device operations
$manager->collect(string $deviceId): ?array
$manager->control(string $deviceId, string $action, $value = null): ?array
$manager->automate(string $deviceId, int $excessPower): ?array

// Batch operations
$manager->collectAllDevices(bool $isCli = false): array
$manager->runAutomations(?array $config = null): array

// Configuration
$manager->getDevice(string $deviceId): ?BaseDevice
$manager->getConfig(string $deviceId): ?array
$manager->listDeviceIds(bool $onlyEnabled = true): array
$manager->setLocale(string $locale): void

// Automation state
$manager->setAutomationOverride(string $deviceId, bool $enabled): bool
$manager->getAutomationOverrideStates(?string $deviceId = null)

// Logging
$manager->getLatestLogEntry(string $deviceId): ?array
$manager->writeLog(string $deviceId, array $data): bool

BaseDevice

All device classes extend BaseDevice:

$device->collect(): ?array
$device->control(string $action, $value = null): array
$device->formatForLog(array $data): array
$device->getCapabilities(): array
$device->getDashboardControls(array $deviceData = []): array
$device->getFieldLabel(string $fieldName): string

Adding Custom Devices

  1. Create a new directory: src/devices/mydevice/
  2. Create the device class:
<?php
namespace Devicemanager\devices;

use Devicemanager\BaseDevice;

class MyDeviceDevice extends BaseDevice
{
    public function collect(): ?array
    {
        $url = "http://{$this->config['host']}/status";
        $response = $this->httpRequest($url);
        
        if (!$response) {
            $this->setLastError('Connection failed');
            return null;
        }
        
        return json_decode($response, true);
    }
    
    public function control(string $action, $value = null): array
    {
        // Implement control logic
        return $this->createSuccessResult();
    }
}
  1. Add language files (optional): src/devices/mydevice/lang/en.php

The device will be auto-discovered and available as type my_device.

Dashboard Integration

The Device Manager integrates with the main dashboard via modules in dashcore/:

Module Purpose
DeviceDashboardModule Device status and control UI
DeviceSetupModule Device configuration interface
DevicePermissionsModule Per-device access control

Permissions

Device permissions are stored in config/permissions.json:

{
  "devices": {
    "wallbox": {
      "view": true,
      "automate": true,
      "control": ["enable", "disable", "set_current"]
    }
  }
}

Or inject a permission checker from the parent application:

$manager->setPermissionChecker(function(string $deviceId, string $action): bool {
    return checkUserPermission("device.{$deviceId}.{$action}");
});

License

MIT License - See LICENSE file for details.

Troubleshooting

Device Not Responding

  1. Check network connectivity: ping <device_ip>
  2. Verify device is enabled in registry
  3. Check logs for error messages
  4. Increase timeout in device config

Automation Not Working

  1. Verify automate: true or automation.enabled: true in device config
  2. Check that solax_main device is collecting power data
  3. Review automation.json for decision logs
  4. Ensure battery threshold conditions are met

Permission Denied

  1. Check config/permissions.json settings
  2. If using external checker, verify callback logic
  3. Review user's device permissions in parent application