feat(domoticz): Add LuCI dashboard with MQTT auto-bridge and Zigbee2MQTT integration

New luci-app-domoticz package with RPCD handler (12 methods), LuCI overview
(status, IoT integration, MQTT, HAProxy, mesh, logs), and full service lifecycle.
Enhanced domoticzctl with configure-mqtt (auto Mosquitto+Z2M bridge), configure-haproxy,
backup/restore, mesh-register, and uninstall commands. UCI extended with mqtt/network/mesh
sections. Catalog updated with LuCI package and IoT tags. MirrorNetworking strategic
document noted in planning files.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-02-04 21:32:17 +01:00
parent 79bb3c43f4
commit 89896568b1
14 changed files with 1198 additions and 44 deletions

View File

@ -136,3 +136,4 @@ _Last updated: 2026-02-04_
- `zigbee2mqtt`: Direct `/dev/ttyUSB0` passthrough (socat TCP bridge fails ASH protocol), adapter `ezsp`→`ember` (z2m 2.x), `ZIGBEE2MQTT_DATA` env var, `mosquitto-nossl` dependency.
- `smbfs`: New SMB/CIFS remote mount manager package — UCI config, `smbfsctl` CLI (add/remove/mount/umount/test/status), auto-mount init script, credentials storage, Jellyfin+Lyrion integration, catalog entry.
- `jellyfin`: KISS READMEs for both backend and LuCI packages.
- `domoticz`: New `luci-app-domoticz` LuCI dashboard with IoT integration status (Mosquitto, Zigbee2MQTT, MQTT bridge), service lifecycle, HAProxy, mesh P2P, logs. `domoticzctl` enhanced with `configure-mqtt` (auto Mosquitto+Z2M bridge), `configure-haproxy`, `backup/restore`, `mesh-register`, `uninstall`. UCI extended with mqtt/network/mesh sections. Catalog updated.

View File

@ -105,3 +105,25 @@ _Last updated: 2026-02-04_
- Decentralized package distribution across mesh nodes.
- Compatible with existing bonus-feed and secubox-feed infrastructure.
- Torrent-style swarming for large IPK downloads across mesh peers.
17. **MirrorNetworking Stack** (ref: `SecuBox_MirrorNetworking_Paradigm_Reversal.html`)
- EnigmaBox paradigm reversal: zero central authority, each box is the network.
- Dual transport: WireGuard (tier 1, known peers) + Yggdrasil (tier 2, discovery/extended mesh, optional).
- New packages roadmap:
- `secubox-mirrornet` (v0.19): Core mesh orchestration, gossip protocol, peer management.
- `secubox-identity` (v0.19): did:plc generation, key rotation, trust scoring.
- `secubox-p2p-intel` (v0.19): IoC signed gossip, threat intelligence sharing.
- `luci-app-secubox-mirror` (v0.19): Dashboard for peers, trust, services, comms.
- `secubox-voip` (v1.0): Asterisk micro-PBX, SIP/SRTP direct over WireGuard mesh.
- `secubox-matrix` (v1.0): Conduit Matrix server (Rust, ~15MB RAM), federation on mesh.
- `secubox-factory` (v1.0): Auto-provisioning new box via mesh P2P.
- `yggdrasil-secubox` (v1.1+): Yggdrasil overlay + meshname DNS.
- Mirror concepts: Threat Intel sharing, AI Inference distribution, Reputation scoring, Config & Updates P2P.
- Communication: VoIP E2E (Asterisk/SRTP, no exit server), Matrix E2EE, optional mesh email.
- ANSSI CSPN: Zero central authority = verifiable sovereignty.
- Crowdfunding target: 2027.
18. **Tor Shield / opkg Bug** (deferred)
- opkg downloads fail (`wget returned 4`) when Tor Shield is active.
- Direct `wget` to full URL works — likely DNS/routing interference.
- Investigate: opkg proxy settings, Tor split-routing exclusions for package repos.

View File

@ -23,18 +23,28 @@
- `SecuBox_LocalAI_Strategic_Analysis.html` — AI Management Layer roadmap (LocalAI 3.9 + LocalAGI + MCP).
- `SecuBox_AI_Gateway_Hybrid_Architecture.html` — Hybrid Local/Cloud architecture (LiteLLM + Data Classifier + multi-provider).
- `SecuBox_MirrorNetworking_Paradigm_Reversal.html` — EnigmaBox autopsy → MirrorNet zero-central-authority architecture. Dual transport (WireGuard + Yggdrasil), VoIP E2E (Asterisk), Matrix/Conduit messaging, did:plc identity, P2P gossip threat intel, Mirror concepts (Threat Intel, AI Inference, Reputation, Config & Updates). New packages: secubox-mirrornet (v0.19), secubox-identity (v0.19), secubox-voip (v1.0), secubox-matrix (v1.0), secubox-p2p-intel (v0.19), yggdrasil-secubox (v1.1+), luci-app-secubox-mirror (v0.19). Crowdfunding target: 2027.
- **Domoticz IoT Integration**
Status: DONE (2026-02-04)
Notes: `luci-app-domoticz` created with RPCD handler, LuCI overview (status, MQTT, Z2M, HAProxy, mesh, logs).
`domoticzctl` enhanced with `configure-mqtt`, `configure-haproxy`, `backup/restore`, `mesh-register`, `uninstall`.
UCI config extended with mqtt, network, mesh sections. Catalog updated with LuCI package and IoT tags.
## Next Up
1. **Domoticz IoT Integration** — LuCI app, MQTT auto-bridge, zigbee2mqtt integration, P2P mesh.
2. **Metablogizer Upload Fixes** — Investigate failed uploads.
3. **App Store P2P Emancipation** — Remote P2P/torrent endpoint, generative IPK distribution.
4. Port chip header layout to client-guardian, auth-guardian.
5. Rebuild bonus feed with all 2026-02-04 changes.
6. Commit uncommitted working tree changes (bonus-feed IPKs, glancesctl, zigbee2mqttctl, smbfs, jellyfin READMEs).
1. **Metablogizer Upload Fixes** — Investigate failed uploads.
2. **App Store P2P Emancipation** — Remote P2P/torrent endpoint, generative IPK distribution.
3. Port chip header layout to client-guardian, auth-guardian.
4. Rebuild bonus feed with all 2026-02-04 changes.
5. Commit uncommitted working tree changes.
## Known Bugs (Deferred)
- **Tor Shield / opkg conflict**: opkg downloads fail (`wget returned 4`) when Tor Shield is active. Direct `wget` to full URL works. Likely DNS/routing interference from Tor split-routing. To be fixed later.
## Blockers / Risks
- No automated regression tests for LuCI views; manual verification required after each SCP deploy.
- Glances + Zigbee2MQTT + SMB/CIFS source changes uncommitted in working tree.
- Strategic AI documents noted but not yet implemented (v0.18+ roadmap).
- Strategic AI + MirrorNetworking documents noted but not yet implemented (v0.18+ roadmap).

View File

@ -0,0 +1,29 @@
include $(TOPDIR)/rules.mk
LUCI_TITLE:=LuCI Domoticz Home Automation Configuration
LUCI_DEPENDS:=+secubox-app-domoticz
LUCI_PKGARCH:=all
PKG_NAME:=luci-app-domoticz
PKG_VERSION:=1.0.0
PKG_RELEASE:=1
PKG_MAINTAINER:=CyberMind Studio <contact@cybermind.fr>
PKG_LICENSE:=Apache-2.0
include $(TOPDIR)/feeds/luci/luci.mk
define Package/luci-app-domoticz/install
$(INSTALL_DIR) $(1)/usr/share/luci/menu.d
$(INSTALL_DATA) ./root/usr/share/luci/menu.d/luci-app-domoticz.json $(1)/usr/share/luci/menu.d/
$(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d
$(INSTALL_DATA) ./root/usr/share/rpcd/acl.d/luci-app-domoticz.json $(1)/usr/share/rpcd/acl.d/
$(INSTALL_DIR) $(1)/www/luci-static/resources/view/domoticz
$(INSTALL_DATA) ./htdocs/luci-static/resources/view/domoticz/*.js $(1)/www/luci-static/resources/view/domoticz/
$(INSTALL_DIR) $(1)/usr/libexec/rpcd
$(INSTALL_BIN) ./root/usr/libexec/rpcd/luci.domoticz $(1)/usr/libexec/rpcd/
endef
$(eval $(call BuildPackage,luci-app-domoticz))

View File

@ -0,0 +1,57 @@
# luci-app-domoticz
LuCI web interface for managing the Domoticz home automation platform on SecuBox.
## Installation
```bash
opkg install luci-app-domoticz
```
Requires `secubox-app-domoticz` (installed as dependency).
## Features
- **Service Status**: Container status, Docker availability, disk usage, USB devices
- **IoT Integration**: Mosquitto broker status, Zigbee2MQTT status, MQTT bridge configuration
- **MQTT Auto-Setup**: One-click Mosquitto installation and broker configuration
- **Network**: HAProxy reverse proxy integration, WAN access control, domain configuration
- **Mesh P2P**: Register Domoticz in the SecuBox P2P mesh for multi-node discovery
- **Actions**: Install, start, stop, restart, update, backup, uninstall
- **Logs**: Live container log viewer
## RPCD Methods
| Method | Params | Description |
|--------|--------|-------------|
| `status` | — | Container, MQTT, Z2M, HAProxy, mesh status |
| `start` | — | Start Domoticz service |
| `stop` | — | Stop Domoticz service |
| `restart` | — | Restart Domoticz service |
| `install` | — | Pull Docker image and configure |
| `uninstall` | — | Remove container (preserves data) |
| `update` | — | Pull latest image and restart |
| `configure_mqtt` | — | Auto-configure Mosquitto and MQTT bridge |
| `configure_haproxy` | — | Register HAProxy vhost |
| `backup` | — | Create data backup |
| `restore` | path | Restore from backup file |
| `logs` | lines | Fetch container logs |
## Menu Location
Services > Domoticz
## Files
- `/usr/libexec/rpcd/luci.domoticz` — RPCD handler
- `/usr/share/rpcd/acl.d/luci-app-domoticz.json` — ACL permissions
- `/usr/share/luci/menu.d/luci-app-domoticz.json` — Menu entry
- `/www/luci-static/resources/view/domoticz/overview.js` — LuCI view
## Dependencies
- `secubox-app-domoticz`
## License
Apache-2.0

View File

@ -0,0 +1,456 @@
'use strict';
'require view';
'require form';
'require uci';
'require rpc';
'require ui';
var callStatus = rpc.declare({
object: 'luci.domoticz',
method: 'status',
expect: {}
});
var callStart = rpc.declare({
object: 'luci.domoticz',
method: 'start',
expect: {}
});
var callStop = rpc.declare({
object: 'luci.domoticz',
method: 'stop',
expect: {}
});
var callRestart = rpc.declare({
object: 'luci.domoticz',
method: 'restart',
expect: {}
});
var callInstall = rpc.declare({
object: 'luci.domoticz',
method: 'install',
expect: {}
});
var callUninstall = rpc.declare({
object: 'luci.domoticz',
method: 'uninstall',
expect: {}
});
var callUpdate = rpc.declare({
object: 'luci.domoticz',
method: 'update',
expect: {}
});
var callConfigureMqtt = rpc.declare({
object: 'luci.domoticz',
method: 'configure_mqtt',
expect: {}
});
var callConfigureHaproxy = rpc.declare({
object: 'luci.domoticz',
method: 'configure_haproxy',
expect: {}
});
var callBackup = rpc.declare({
object: 'luci.domoticz',
method: 'backup',
expect: {}
});
var callLogs = rpc.declare({
object: 'luci.domoticz',
method: 'logs',
params: ['lines'],
expect: {}
});
function statusColor(val) {
if (val === 'running' || val === 'configured') return '#27ae60';
if (val === 'stopped' || val === 'pending') return '#e74c3c';
return '#8892b0';
}
function statusLabel(val) {
if (val === 'running') return 'Running';
if (val === 'stopped') return 'Stopped';
if (val === 'not_installed') return 'Not Installed';
if (val === 'configured') return 'Configured';
if (val === 'pending') return 'Pending';
if (val === 'disabled') return 'Disabled';
return val || 'Unknown';
}
return view.extend({
load: function() {
return Promise.all([
uci.load('domoticz'),
callStatus()
]);
},
render: function(data) {
var status = data[1] || {};
var m, s, o;
m = new form.Map('domoticz', _('Domoticz Home Automation'),
_('Open-source home automation platform with IoT device management, MQTT bridge, and Zigbee integration.'));
/* ---- Service Status ---- */
s = m.section(form.NamedSection, 'main', 'domoticz', _('Service Status'));
s.anonymous = true;
o = s.option(form.DummyValue, '_status', _('Status'));
o.rawhtml = true;
o.cfgvalue = function() {
var cs = status.container_status || 'unknown';
var color = statusColor(cs);
var label = statusLabel(cs);
var html = '<span style="color:' + color + '; font-weight:bold;">' + label + '</span>';
if (cs === 'running' && status.container_uptime)
html += ' <span style="color:#8892b0;">(' + status.container_uptime + ')</span>';
return html;
};
o = s.option(form.DummyValue, '_docker', _('Docker'));
o.rawhtml = true;
o.cfgvalue = function() {
return status.docker_available
? '<span style="color:#27ae60;">Available</span>'
: '<span style="color:#e74c3c;">Not available</span>';
};
o = s.option(form.DummyValue, '_info', _('Details'));
o.rawhtml = true;
o.cfgvalue = function() {
var port = status.port || 8080;
var html = '<table style="border-collapse:collapse;">';
html += '<tr><td style="padding:2px 12px 2px 0;color:#8892b0;">Image:</td><td>' + (status.image || '-') + '</td></tr>';
html += '<tr><td style="padding:2px 12px 2px 0;color:#8892b0;">Port:</td><td>' + port + '</td></tr>';
html += '<tr><td style="padding:2px 12px 2px 0;color:#8892b0;">Data:</td><td>' + (status.data_path || '-') + '</td></tr>';
html += '<tr><td style="padding:2px 12px 2px 0;color:#8892b0;">Domain:</td><td>' + (status.domain || '-') + '</td></tr>';
if (status.disk_usage)
html += '<tr><td style="padding:2px 12px 2px 0;color:#8892b0;">Disk:</td><td>' + status.disk_usage + '</td></tr>';
if (status.usb_devices && status.usb_devices.length > 0)
html += '<tr><td style="padding:2px 12px 2px 0;color:#8892b0;">USB:</td><td>' + status.usb_devices.join(', ') + '</td></tr>';
html += '</table>';
return html;
};
/* ---- IoT Integration Status ---- */
o = s.option(form.DummyValue, '_iot', _('IoT Integration'));
o.rawhtml = true;
o.cfgvalue = function() {
var html = '<table style="border-collapse:collapse;">';
// Mosquitto
var mc = statusColor(status.mosquitto_status);
html += '<tr><td style="padding:2px 12px 2px 0;color:#8892b0;">Mosquitto:</td>';
html += '<td style="color:' + mc + ';">' + statusLabel(status.mosquitto_status) + '</td></tr>';
// Zigbee2MQTT
var zc = statusColor(status.z2m_status);
var zl = statusLabel(status.z2m_status);
if (status.z2m_status === 'running' && status.z2m_port)
zl += ' (port ' + status.z2m_port + ')';
html += '<tr><td style="padding:2px 12px 2px 0;color:#8892b0;">Zigbee2MQTT:</td>';
html += '<td style="color:' + zc + ';">' + zl + '</td></tr>';
// MQTT bridge
var be = status.mqtt_enabled ? '#27ae60' : '#8892b0';
var bl = status.mqtt_enabled
? 'Enabled (' + (status.mqtt_broker || '127.0.0.1') + ':' + (status.mqtt_broker_port || 1883) + ')'
: 'Disabled';
html += '<tr><td style="padding:2px 12px 2px 0;color:#8892b0;">MQTT Bridge:</td>';
html += '<td style="color:' + be + ';">' + bl + '</td></tr>';
html += '</table>';
return html;
};
/* ---- Network Integration ---- */
o = s.option(form.DummyValue, '_integrations', _('Network'));
o.rawhtml = true;
o.cfgvalue = function() {
var html = '<table style="border-collapse:collapse;">';
var hc = '#8892b0', hl = 'Disabled';
if (status.haproxy_status === 'configured') {
hc = '#27ae60'; hl = 'Configured (' + (status.domain || '') + ')';
} else if (status.haproxy_status === 'pending') {
hc = '#f39c12'; hl = 'Enabled (not yet configured)';
}
html += '<tr><td style="padding:2px 12px 2px 0;color:#8892b0;">HAProxy:</td><td style="color:' + hc + ';">' + hl + '</td></tr>';
var meshc = status.mesh_enabled ? '#27ae60' : '#8892b0';
var meshl = status.mesh_enabled ? 'Enabled' : 'Disabled';
html += '<tr><td style="padding:2px 12px 2px 0;color:#8892b0;">Mesh P2P:</td><td style="color:' + meshc + ';">' + meshl + '</td></tr>';
var fc = status.firewall_wan ? '#27ae60' : '#8892b0';
var fl = status.firewall_wan ? 'WAN access on port ' + (status.port || 8080) : 'LAN only';
html += '<tr><td style="padding:2px 12px 2px 0;color:#8892b0;">Firewall:</td><td style="color:' + fc + ';">' + fl + '</td></tr>';
html += '</table>';
return html;
};
/* ---- Action Buttons ---- */
var cs = status.container_status || 'not_installed';
if (cs === 'not_installed') {
o = s.option(form.Button, '_install', _('Install'));
o.inputtitle = _('Install Domoticz');
o.inputstyle = 'apply';
o.onclick = function() {
ui.showModal(_('Installing...'), [
E('p', { 'class': 'spinning' }, _('Pulling Docker image and configuring...'))
]);
return callInstall().then(function(res) {
ui.hideModal();
if (res && res.success) {
ui.addNotification(null, E('p', {}, _('Domoticz installed successfully.')), 'info');
} else {
ui.addNotification(null, E('p', {}, _('Installation failed: ') + (res.output || 'Unknown error')), 'danger');
}
window.location.href = window.location.pathname + '?' + Date.now();
});
};
} else {
if (cs === 'stopped') {
o = s.option(form.Button, '_start', _('Start'));
o.inputtitle = _('Start');
o.inputstyle = 'apply';
o.onclick = function() {
return callStart().then(function() {
window.location.href = window.location.pathname + '?' + Date.now();
});
};
}
if (cs === 'running') {
o = s.option(form.Button, '_stop', _('Stop'));
o.inputtitle = _('Stop');
o.inputstyle = 'remove';
o.onclick = function() {
return callStop().then(function() {
window.location.href = window.location.pathname + '?' + Date.now();
});
};
o = s.option(form.Button, '_restart', _('Restart'));
o.inputtitle = _('Restart');
o.inputstyle = 'reload';
o.onclick = function() {
return callRestart().then(function() {
window.location.href = window.location.pathname + '?' + Date.now();
});
};
o = s.option(form.Button, '_webui', _('Web UI'));
o.inputtitle = _('Open Domoticz UI');
o.inputstyle = 'action';
o.onclick = function() {
var port = status.port || 8080;
window.open('http://' + window.location.hostname + ':' + port, '_blank');
};
}
o = s.option(form.Button, '_update', _('Update'));
o.inputtitle = _('Pull Latest Image');
o.inputstyle = 'action';
o.onclick = function() {
ui.showModal(_('Updating...'), [
E('p', { 'class': 'spinning' }, _('Pulling latest Docker image and restarting...'))
]);
return callUpdate().then(function(res) {
ui.hideModal();
if (res && res.success) {
ui.addNotification(null, E('p', {}, _('Domoticz updated successfully.')), 'info');
} else {
ui.addNotification(null, E('p', {}, _('Update failed: ') + (res.output || 'Unknown error')), 'danger');
}
window.location.href = window.location.pathname + '?' + Date.now();
});
};
o = s.option(form.Button, '_backup', _('Backup'));
o.inputtitle = _('Create Backup');
o.inputstyle = 'action';
o.onclick = function() {
return callBackup().then(function(res) {
if (res && res.success) {
ui.addNotification(null, E('p', {}, _('Backup created: ') + (res.path || '')), 'info');
} else {
ui.addNotification(null, E('p', {}, _('Backup failed: ') + (res.output || 'Unknown error')), 'danger');
}
});
};
o = s.option(form.Button, '_uninstall', _('Uninstall'));
o.inputtitle = _('Uninstall');
o.inputstyle = 'remove';
o.onclick = function() {
if (!confirm(_('Are you sure you want to uninstall Domoticz? Data will be preserved.')))
return;
ui.showModal(_('Uninstalling...'), [
E('p', { 'class': 'spinning' }, _('Removing container and integrations...'))
]);
return callUninstall().then(function(res) {
ui.hideModal();
if (res && res.success) {
ui.addNotification(null, E('p', {}, _('Domoticz uninstalled.')), 'info');
} else {
ui.addNotification(null, E('p', {}, _('Uninstall failed: ') + (res.output || 'Unknown error')), 'danger');
}
window.location.href = window.location.pathname + '?' + Date.now();
});
};
}
/* ---- Configuration Section ---- */
s = m.section(form.NamedSection, 'main', 'domoticz', _('Configuration'));
s.anonymous = true;
o = s.option(form.Flag, 'enabled', _('Enabled'),
_('Enable the Domoticz service.'));
o.rmempty = false;
o = s.option(form.Value, 'port', _('Port'),
_('HTTP port for the Domoticz web interface.'));
o.datatype = 'port';
o.placeholder = '8080';
o = s.option(form.Value, 'image', _('Docker Image'),
_('Docker image to use.'));
o.placeholder = 'domoticz/domoticz:latest';
o = s.option(form.Value, 'data_path', _('Data Path'),
_('Path for Domoticz config and database.'));
o.placeholder = '/srv/domoticz';
o = s.option(form.Value, 'devices_path', _('Devices Path'),
_('Path for USB device passthrough into container.'));
o.placeholder = '/srv/devices';
o = s.option(form.Value, 'timezone', _('Timezone'));
o.placeholder = 'Europe/Paris';
/* ---- MQTT & Zigbee Section ---- */
s = m.section(form.NamedSection, 'mqtt', 'domoticz', _('MQTT & Zigbee'));
s.anonymous = true;
o = s.option(form.Flag, 'enabled', _('MQTT Bridge'),
_('Auto-configure Domoticz MQTT connection to the local Mosquitto broker.'));
o.rmempty = false;
o = s.option(form.Value, 'broker', _('MQTT Broker'),
_('Mosquitto broker address.'));
o.placeholder = '127.0.0.1';
o.depends('enabled', '1');
o = s.option(form.Value, 'broker_port', _('MQTT Port'),
_('Mosquitto broker port.'));
o.datatype = 'port';
o.placeholder = '1883';
o.depends('enabled', '1');
o = s.option(form.Value, 'topic_prefix', _('Domoticz Topic'),
_('MQTT topic prefix for Domoticz messages.'));
o.placeholder = 'domoticz';
o.depends('enabled', '1');
o = s.option(form.Value, 'z2m_topic', _('Zigbee2MQTT Topic'),
_('MQTT topic where Zigbee2MQTT publishes device data.'));
o.placeholder = 'zigbee2mqtt';
o.depends('enabled', '1');
o = s.option(form.Button, '_setup_mqtt', _('Auto-Configure'));
o.inputtitle = _('Setup MQTT Bridge');
o.inputstyle = 'apply';
o.depends('enabled', '1');
o.onclick = function() {
ui.showModal(_('Configuring MQTT...'), [
E('p', { 'class': 'spinning' }, _('Setting up Mosquitto broker and Domoticz MQTT connection...'))
]);
return callConfigureMqtt().then(function(res) {
ui.hideModal();
if (res && res.success) {
ui.addNotification(null, E('p', {}, _('MQTT bridge configured successfully.')), 'info');
} else {
ui.addNotification(null, E('p', {}, _('MQTT setup failed: ') + (res.output || 'Unknown error')), 'danger');
}
window.location.href = window.location.pathname + '?' + Date.now();
});
};
/* ---- Network & Domain Section ---- */
s = m.section(form.NamedSection, 'network', 'domoticz', _('Network & Domain'));
s.anonymous = true;
o = s.option(form.Value, 'domain', _('Domain'),
_('Domain name for accessing Domoticz via HAProxy reverse proxy.'));
o.placeholder = 'domoticz.secubox.local';
o = s.option(form.Flag, 'haproxy', _('HAProxy Integration'),
_('Register Domoticz as an HAProxy vhost for reverse proxy access.'));
o.rmempty = false;
o = s.option(form.Flag, 'firewall_wan', _('WAN Access'),
_('Allow direct WAN access to the Domoticz port.'));
o.rmempty = false;
o = s.option(form.Button, '_apply_haproxy', _('Apply HAProxy'));
o.inputtitle = _('Configure HAProxy Now');
o.inputstyle = 'action';
o.depends('haproxy', '1');
o.onclick = function() {
return callConfigureHaproxy().then(function(res) {
if (res && res.success) {
ui.addNotification(null, E('p', {}, _('HAProxy configured successfully.')), 'info');
} else {
ui.addNotification(null, E('p', {}, _('HAProxy configuration failed: ') + (res.output || 'Unknown error')), 'danger');
}
});
};
/* ---- Mesh P2P Section ---- */
s = m.section(form.NamedSection, 'mesh', 'domoticz', _('Mesh P2P'));
s.anonymous = true;
o = s.option(form.Flag, 'enabled', _('Mesh Integration'),
_('Register Domoticz with the SecuBox P2P mesh network for discovery by other nodes.'));
o.rmempty = false;
/* ---- Logs Section ---- */
s = m.section(form.NamedSection, 'main', 'domoticz', _('Logs'));
s.anonymous = true;
o = s.option(form.DummyValue, '_logs', ' ');
o.rawhtml = true;
o.cfgvalue = function() {
return '<div id="domoticz-logs" style="background:#0a0a1a; color:#ccc; padding:8px; ' +
'border-radius:4px; font-family:monospace; font-size:12px; max-height:300px; ' +
'overflow-y:auto; white-space:pre-wrap; min-height:40px;">Click "Fetch Logs" to view container output.</div>';
};
o = s.option(form.Button, '_fetch_logs', _('Fetch Logs'));
o.inputtitle = _('Fetch Logs');
o.inputstyle = 'action';
o.onclick = function() {
var logsDiv = document.getElementById('domoticz-logs');
if (logsDiv) logsDiv.textContent = 'Loading...';
return callLogs(50).then(function(res) {
if (logsDiv) logsDiv.textContent = (res && res.logs) ? res.logs : 'No logs available.';
});
};
return m.render();
}
});

View File

@ -0,0 +1,237 @@
#!/bin/sh
. /lib/functions.sh
. /usr/share/libubox/jshn.sh
CONTAINER="secbx-domoticz"
CONFIG="domoticz"
case "$1" in
list)
echo '{"status":{},"start":{},"stop":{},"restart":{},"install":{},"uninstall":{},"update":{},"configure_mqtt":{},"configure_haproxy":{},"backup":{},"restore":{"path":"str"},"logs":{"lines":"int"}}'
;;
call)
case "$2" in
status)
json_init
enabled=$(uci -q get ${CONFIG}.main.enabled)
image=$(uci -q get ${CONFIG}.main.image)
port=$(uci -q get ${CONFIG}.main.port)
data_path=$(uci -q get ${CONFIG}.main.data_path)
devices_path=$(uci -q get ${CONFIG}.main.devices_path)
timezone=$(uci -q get ${CONFIG}.main.timezone)
# MQTT config
mqtt_enabled=$(uci -q get ${CONFIG}.mqtt.enabled)
mqtt_broker=$(uci -q get ${CONFIG}.mqtt.broker)
mqtt_broker_port=$(uci -q get ${CONFIG}.mqtt.broker_port)
mqtt_topic_prefix=$(uci -q get ${CONFIG}.mqtt.topic_prefix)
mqtt_z2m_topic=$(uci -q get ${CONFIG}.mqtt.z2m_topic)
# Network/domain config
domain=$(uci -q get ${CONFIG}.network.domain)
haproxy=$(uci -q get ${CONFIG}.network.haproxy)
firewall_wan=$(uci -q get ${CONFIG}.network.firewall_wan)
# Mesh config
mesh_enabled=$(uci -q get ${CONFIG}.mesh.enabled)
json_add_boolean "enabled" ${enabled:-0}
json_add_string "image" "${image:-domoticz/domoticz:latest}"
json_add_int "port" ${port:-8080}
json_add_string "data_path" "${data_path:-/srv/domoticz}"
json_add_string "devices_path" "${devices_path:-/srv/devices}"
json_add_string "timezone" "${timezone:-UTC}"
json_add_boolean "mqtt_enabled" ${mqtt_enabled:-0}
json_add_string "mqtt_broker" "${mqtt_broker:-127.0.0.1}"
json_add_int "mqtt_broker_port" ${mqtt_broker_port:-1883}
json_add_string "mqtt_topic_prefix" "${mqtt_topic_prefix:-domoticz}"
json_add_string "mqtt_z2m_topic" "${mqtt_z2m_topic:-zigbee2mqtt}"
json_add_string "domain" "${domain:-domoticz.secubox.local}"
json_add_boolean "haproxy" ${haproxy:-0}
json_add_boolean "firewall_wan" ${firewall_wan:-0}
json_add_boolean "mesh_enabled" ${mesh_enabled:-0}
# Docker availability
if command -v docker >/dev/null 2>&1; then
json_add_boolean "docker_available" 1
else
json_add_boolean "docker_available" 0
fi
# Container status
if docker ps --filter "name=$CONTAINER" --format '{{.Status}}' 2>/dev/null | grep -q .; then
json_add_string "container_status" "running"
uptime=$(docker ps --filter "name=$CONTAINER" --format '{{.Status}}' 2>/dev/null)
json_add_string "container_uptime" "$uptime"
elif docker ps -a --filter "name=$CONTAINER" --format '{{.Status}}' 2>/dev/null | grep -q .; then
json_add_string "container_status" "stopped"
json_add_string "container_uptime" ""
else
json_add_string "container_status" "not_installed"
json_add_string "container_uptime" ""
fi
# Mosquitto broker status
if pgrep mosquitto >/dev/null 2>&1; then
json_add_string "mosquitto_status" "running"
elif command -v mosquitto >/dev/null 2>&1; then
json_add_string "mosquitto_status" "stopped"
else
json_add_string "mosquitto_status" "not_installed"
fi
# Zigbee2MQTT status
z2m_running=0
if [ -f /srv/zigbee2mqtt/alpine/rootfs/run.pid ]; then
z2m_running=1
elif pgrep -f zigbee2mqtt >/dev/null 2>&1; then
z2m_running=1
fi
if [ "$z2m_running" = "1" ]; then
json_add_string "z2m_status" "running"
z2m_port=$(uci -q get zigbee2mqtt.main.frontend_port)
json_add_int "z2m_port" ${z2m_port:-8099}
elif [ -f /etc/config/zigbee2mqtt ]; then
json_add_string "z2m_status" "stopped"
json_add_int "z2m_port" 0
else
json_add_string "z2m_status" "not_installed"
json_add_int "z2m_port" 0
fi
# HAProxy vhost status
if [ "${haproxy:-0}" = "1" ]; then
vhost_exists=$(uci show haproxy 2>/dev/null | grep "\.domain='${domain:-domoticz.secubox.local}'" | head -1)
if [ -n "$vhost_exists" ]; then
json_add_string "haproxy_status" "configured"
else
json_add_string "haproxy_status" "pending"
fi
else
json_add_string "haproxy_status" "disabled"
fi
# Disk usage
dp="${data_path:-/srv/domoticz}"
if [ -d "$dp" ]; then
disk_usage=$(du -sh "$dp" 2>/dev/null | cut -f1)
json_add_string "disk_usage" "${disk_usage:-0}"
else
json_add_string "disk_usage" ""
fi
# USB devices
json_add_array "usb_devices"
for dev in /dev/ttyUSB* /dev/ttyACM*; do
[ -e "$dev" ] && json_add_string "" "$dev"
done
json_close_array
json_dump
;;
start)
/etc/init.d/domoticz start >/dev/null 2>&1
echo '{"success":true}'
;;
stop)
/etc/init.d/domoticz stop >/dev/null 2>&1
echo '{"success":true}'
;;
restart)
/etc/init.d/domoticz restart >/dev/null 2>&1
echo '{"success":true}'
;;
install)
output=$(/usr/sbin/domoticzctl install 2>&1)
code=$?
json_init
json_add_boolean "success" $((code == 0))
json_add_string "output" "$output"
json_dump
;;
uninstall)
output=$(/usr/sbin/domoticzctl uninstall 2>&1)
code=$?
json_init
json_add_boolean "success" $((code == 0))
json_add_string "output" "$output"
json_dump
;;
update)
output=$(/usr/sbin/domoticzctl update 2>&1)
code=$?
json_init
json_add_boolean "success" $((code == 0))
json_add_string "output" "$output"
json_dump
;;
configure_mqtt)
output=$(/usr/sbin/domoticzctl configure-mqtt 2>&1)
code=$?
json_init
json_add_boolean "success" $((code == 0))
json_add_string "output" "$output"
json_dump
;;
configure_haproxy)
output=$(/usr/sbin/domoticzctl configure-haproxy 2>&1)
code=$?
json_init
json_add_boolean "success" $((code == 0))
json_add_string "output" "$output"
json_dump
;;
backup)
backup_file="/tmp/domoticz-backup-$(date +%Y%m%d-%H%M%S).tar.gz"
output=$(/usr/sbin/domoticzctl backup "$backup_file" 2>&1)
code=$?
json_init
json_add_boolean "success" $((code == 0))
json_add_string "path" "$backup_file"
json_add_string "output" "$output"
json_dump
;;
restore)
read -r input
path=$(echo "$input" | jsonfilter -e '@.path' 2>/dev/null)
if [ -z "$path" ]; then
echo '{"success":false,"output":"No backup path specified"}'
else
output=$(/usr/sbin/domoticzctl restore "$path" 2>&1)
code=$?
json_init
json_add_boolean "success" $((code == 0))
json_add_string "output" "$output"
json_dump
fi
;;
logs)
read -r input
lines=$(echo "$input" | jsonfilter -e '@.lines' 2>/dev/null)
[ -z "$lines" ] && lines=50
logs=$(docker logs --tail "$lines" "$CONTAINER" 2>&1 | tail -100)
json_init
json_add_string "logs" "$logs"
json_dump
;;
esac
;;
esac
exit 0

View File

@ -0,0 +1,14 @@
{
"admin/services/domoticz": {
"title": "Domoticz",
"order": 65,
"action": {
"type": "view",
"path": "domoticz/overview"
},
"depends": {
"acl": ["luci-app-domoticz"],
"uci": {"domoticz": true}
}
}
}

View File

@ -0,0 +1,24 @@
{
"luci-app-domoticz": {
"description": "Grant access to Domoticz home automation configuration",
"read": {
"file": {
"/etc/config/domoticz": ["read"]
},
"ubus": {
"file": ["read", "stat"],
"luci.domoticz": ["*"]
},
"uci": ["domoticz"]
},
"write": {
"file": {
"/etc/config/domoticz": ["write"]
},
"ubus": {
"luci.domoticz": ["*"]
},
"uci": ["domoticz"]
}
}
}

View File

@ -1,7 +1,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=secubox-app-domoticz
PKG_RELEASE:=2
PKG_RELEASE:=3
PKG_VERSION:=1.0.0
PKG_ARCH:=all
PKG_MAINTAINER:=CyberMind Studio <contact@cybermind.fr>

View File

@ -1,11 +1,13 @@
# SecuBox Domoticz
Home automation platform running in Docker on SecuBox-powered OpenWrt systems.
Home automation platform running in Docker with MQTT bridge, Zigbee2MQTT integration, and P2P mesh support.
## Installation
```sh
opkg install secubox-app-domoticz
domoticzctl install
/etc/init.d/domoticz start
```
## Configuration
@ -15,33 +17,70 @@ UCI config file: `/etc/config/domoticz`
```
config domoticz 'main'
option enabled '0'
option image 'domoticz/domoticz:latest'
option data_path '/srv/domoticz'
option devices_path '/srv/devices'
option port '8080'
option timezone 'UTC'
config domoticz 'mqtt'
option enabled '0'
option broker '127.0.0.1'
option broker_port '1883'
option topic_prefix 'domoticz'
option z2m_topic 'zigbee2mqtt'
config domoticz 'network'
option domain 'domoticz.secubox.local'
option haproxy '0'
option firewall_wan '0'
config domoticz 'mesh'
option enabled '0'
```
## Usage
```sh
# Start / stop the service
/etc/init.d/domoticz start
/etc/init.d/domoticz stop
# Controller CLI
domoticzctl status
domoticzctl install
domoticzctl remove
domoticzctl install # Pull image, install prerequisites
domoticzctl uninstall # Remove container (data preserved)
domoticzctl update # Pull latest image, restart
domoticzctl status # Show container status
domoticzctl logs [-f] # Container logs
domoticzctl configure-mqtt # Auto-setup Mosquitto + MQTT bridge
domoticzctl configure-haproxy # Register HAProxy vhost
domoticzctl backup [path] # Backup data
domoticzctl restore <path> # Restore from backup
domoticzctl mesh-register # Register in P2P mesh
```
## MQTT Bridge
The `configure-mqtt` command auto-configures:
1. Installs `mosquitto-nossl` if not present
2. Configures Mosquitto listener on port 1883
3. Detects Zigbee2MQTT broker settings for compatibility
4. Stores MQTT config in UCI for persistence
After setup, add MQTT hardware in Domoticz UI: Setup > Hardware > MQTT Client Gateway.
## Zigbee Integration
When `secubox-app-zigbee2mqtt` is installed:
- Both services share the same Mosquitto broker
- Zigbee devices publish on the `zigbee2mqtt/#` topic
- Domoticz subscribes via MQTT Client Gateway hardware
## Files
- `/etc/config/domoticz` -- UCI configuration
- `/etc/init.d/domoticz` -- init script
- `/etc/init.d/domoticz` -- init script (procd)
- `/usr/sbin/domoticzctl` -- controller CLI
## Dependencies
- `dockerd`
- `docker`
- `containerd`
- `dockerd`, `docker`, `containerd`
- Optional: `mosquitto-nossl`, `secubox-app-zigbee2mqtt`
## License

View File

@ -5,3 +5,18 @@ config domoticz 'main'
option devices_path '/srv/devices'
option port '8080'
option timezone 'UTC'
config domoticz 'mqtt'
option enabled '0'
option broker '127.0.0.1'
option broker_port '1883'
option topic_prefix 'domoticz'
option z2m_topic 'zigbee2mqtt'
config domoticz 'network'
option domain 'domoticz.secubox.local'
option haproxy '0'
option firewall_wan '0'
config domoticz 'mesh'
option enabled '0'

View File

@ -1,5 +1,5 @@
#!/bin/sh
# SecuBox Domoticz manager
# SecuBox Domoticz manager — IoT home automation with MQTT/Zigbee integration
CONFIG="domoticz"
CONTAINER="secbx-domoticz"
@ -10,19 +10,28 @@ usage() {
Usage: domoticzctl <command>
Commands:
install Install prerequisites, prepare directories, pull image
check Run prerequisite checks
update Pull new image and restart
status Show container status
logs Show container logs (use -f to follow)
service-run Internal: run container via procd
service-stop Stop container
install Install prerequisites, prepare directories, pull image
uninstall Remove container (preserves data)
check Run prerequisite checks
update Pull new image and restart
status Show container status
logs [-f] Show container logs (use -f to follow)
configure-mqtt Auto-configure Mosquitto broker and Domoticz MQTT bridge
configure-haproxy Register as HAProxy vhost for reverse proxy
backup [path] Backup Domoticz data
restore <path> Restore Domoticz from backup
mesh-register Register Domoticz in P2P mesh service catalog
service-run Internal: run container via procd
service-stop Stop container
USAGE
}
require_root() { [ "$(id -u)" -eq 0 ]; }
uci_get() { uci -q get ${CONFIG}.main.$1; }
uci_get() {
local section="${2:-main}"
uci -q get ${CONFIG}.${section}.$1
}
defaults() {
image="$(uci_get image || echo domoticz/domoticz:latest)"
@ -36,7 +45,7 @@ ensure_dir() { [ -d "$1" ] || mkdir -p "$1"; }
ensure_packages() {
for pkg in "$@"; do
if ! opkg status "$pkg" >/dev/null 2>&1; then
if ! opkg status "$pkg" 2>/dev/null | grep -q "Status:.*installed"; then
if [ "$OPKG_UPDATED" -eq 0 ]; then
opkg update || return 1
OPKG_UPDATED=1
@ -57,49 +66,268 @@ check_prereqs() {
pull_image() { defaults; docker pull "$image"; }
stop_container() { docker stop "$CONTAINER" >/dev/null 2>&1 || true; docker rm "$CONTAINER" >/dev/null 2>&1 || true; }
stop_container() {
docker stop "$CONTAINER" >/dev/null 2>&1 || true
docker rm "$CONTAINER" >/dev/null 2>&1 || true
}
cmd_install() {
require_root || { echo Root required >&2; exit 1; }
require_root || { echo "Root required" >&2; exit 1; }
check_prereqs || exit 1
ensure_dir "$data_path/config"
pull_image || exit 1
uci set ${CONFIG}.main.enabled='1'
uci commit ${CONFIG}
/etc/init.d/domoticz enable
echo "Domoticz prerequisites installed. Start with /etc/init.d/domoticz start"
echo "Domoticz installed. Start with /etc/init.d/domoticz start"
}
cmd_uninstall() {
require_root || { echo "Root required" >&2; exit 1; }
/etc/init.d/domoticz stop >/dev/null 2>&1
stop_container
defaults
docker rmi "$image" >/dev/null 2>&1 || true
uci set ${CONFIG}.main.enabled='0'
uci commit ${CONFIG}
/etc/init.d/domoticz disable >/dev/null 2>&1
echo "Domoticz uninstalled. Data preserved at ${data_path}."
}
cmd_check() { check_prereqs; echo "Prerequisite check completed."; }
cmd_update() {
require_root || { echo Root required >&2; exit 1; }
require_root || { echo "Root required" >&2; exit 1; }
pull_image || exit 1
/etc/init.d/domoticz restart
echo "Domoticz updated and restarted."
}
cmd_status() { docker ps -a --filter "name=$CONTAINER"; }
cmd_logs() { docker logs "$@" "$CONTAINER"; }
cmd_configure_mqtt() {
require_root || { echo "Root required" >&2; exit 1; }
local broker=$(uci_get broker mqtt)
local broker_port=$(uci_get broker_port mqtt)
local topic_prefix=$(uci_get topic_prefix mqtt)
local z2m_topic=$(uci_get z2m_topic mqtt)
broker="${broker:-127.0.0.1}"
broker_port="${broker_port:-1883}"
topic_prefix="${topic_prefix:-domoticz}"
z2m_topic="${z2m_topic:-zigbee2mqtt}"
# Ensure Mosquitto is installed and running
if ! command -v mosquitto >/dev/null 2>&1; then
echo "Installing mosquitto-nossl..."
ensure_packages mosquitto-nossl mosquitto-client-nossl || {
echo "[ERROR] Failed to install Mosquitto" >&2
return 1
}
fi
# Configure Mosquitto listener
local mosquitto_conf="/etc/mosquitto/mosquitto.conf"
if [ -f "$mosquitto_conf" ]; then
# Ensure listener on configured port
if ! grep -q "^listener ${broker_port}" "$mosquitto_conf" 2>/dev/null; then
echo "" >> "$mosquitto_conf"
echo "# Auto-configured by domoticzctl" >> "$mosquitto_conf"
echo "listener ${broker_port}" >> "$mosquitto_conf"
echo "allow_anonymous true" >> "$mosquitto_conf"
fi
fi
# Start Mosquitto
/etc/init.d/mosquitto enable >/dev/null 2>&1
/etc/init.d/mosquitto start >/dev/null 2>&1
# Verify broker is listening
local retries=0
while [ $retries -lt 5 ]; do
if netstat -tln 2>/dev/null | grep -q ":${broker_port} "; then
break
fi
retries=$((retries + 1))
sleep 1
done
if ! netstat -tln 2>/dev/null | grep -q ":${broker_port} "; then
echo "[WARN] Mosquitto may not be listening on port ${broker_port}" >&2
fi
# Check zigbee2mqtt MQTT settings
if [ -f /etc/config/zigbee2mqtt ]; then
local z2m_mqtt_uri=$(uci -q get zigbee2mqtt.main.mqtt_host)
local z2m_base=$(uci -q get zigbee2mqtt.main.base_topic)
# z2m stores full URI (mqtt://host:port) — extract host and port
local z2m_host=$(echo "$z2m_mqtt_uri" | sed 's|^mqtt[s]*://||' | cut -d: -f1)
local z2m_port_conf=$(echo "$z2m_mqtt_uri" | sed 's|^mqtt[s]*://||' | cut -d: -f2)
z2m_host="${z2m_host:-127.0.0.1}"
z2m_port_conf="${z2m_port_conf:-1883}"
if [ "$z2m_host" = "$broker" ] && [ "$z2m_port_conf" = "$broker_port" ]; then
echo "Zigbee2MQTT shares same broker (${broker}:${broker_port})."
echo "z2m topic: ${z2m_base:-zigbee2mqtt}"
else
echo "[INFO] Zigbee2MQTT uses broker ${z2m_host}:${z2m_port_conf}"
echo "[INFO] Domoticz will connect to ${broker}:${broker_port}"
echo "[INFO] Ensure both use the same Mosquitto broker for device bridging."
fi
else
echo "[INFO] Zigbee2MQTT not installed — MQTT bridge will work with other MQTT publishers."
fi
# Update UCI MQTT settings
uci set ${CONFIG}.mqtt.enabled='1'
uci set ${CONFIG}.mqtt.broker="$broker"
uci set ${CONFIG}.mqtt.broker_port="$broker_port"
uci set ${CONFIG}.mqtt.topic_prefix="$topic_prefix"
uci set ${CONFIG}.mqtt.z2m_topic="$z2m_topic"
uci commit ${CONFIG}
# Note: Domoticz MQTT configuration happens inside the Domoticz web UI
# (Hardware > MQTT Client Gateway). We configure the broker and topic,
# but the user must add the MQTT hardware in Domoticz UI.
echo ""
echo "MQTT bridge configured:"
echo " Broker: ${broker}:${broker_port}"
echo " Domoticz: topic_prefix=${topic_prefix}"
echo " Z2M: topic=${z2m_topic}"
echo ""
echo "Next step: In Domoticz UI (Setup > Hardware), add:"
echo " Type: MQTT Client Gateway with LAN interface"
echo " Remote Address: ${broker}"
echo " Port: ${broker_port}"
echo " Topic prefix: ${topic_prefix}"
}
cmd_configure_haproxy() {
require_root || { echo "Root required" >&2; exit 1; }
local domain=$(uci_get domain network)
local port_val=$(uci_get port)
domain="${domain:-domoticz.secubox.local}"
port_val="${port_val:-8080}"
# Use haproxyctl if available
if command -v haproxyctl >/dev/null 2>&1; then
haproxyctl add-vhost "$domain" "127.0.0.1:${port_val}" 2>&1
local code=$?
if [ $code -eq 0 ]; then
uci set ${CONFIG}.network.haproxy='1'
uci commit ${CONFIG}
echo "HAProxy vhost configured for ${domain} -> 127.0.0.1:${port_val}"
else
echo "[ERROR] haproxyctl add-vhost failed" >&2
return 1
fi
else
echo "[ERROR] haproxyctl not found — install secubox-app-haproxy first" >&2
return 1
fi
}
cmd_backup() {
require_root || { echo "Root required" >&2; exit 1; }
defaults
local backup_path="${1:-/tmp/domoticz-backup-$(date +%Y%m%d-%H%M%S).tar.gz}"
if [ ! -d "$data_path/config" ]; then
echo "[ERROR] No data to backup at ${data_path}/config" >&2
return 1
fi
tar czf "$backup_path" -C "$data_path" config 2>&1
local code=$?
if [ $code -eq 0 ]; then
echo "Backup created: ${backup_path}"
else
echo "[ERROR] Backup failed" >&2
return 1
fi
}
cmd_restore() {
require_root || { echo "Root required" >&2; exit 1; }
defaults
local backup_path="$1"
if [ -z "$backup_path" ] || [ ! -f "$backup_path" ]; then
echo "[ERROR] Backup file not found: ${backup_path}" >&2
return 1
fi
# Stop service before restore
/etc/init.d/domoticz stop >/dev/null 2>&1
stop_container
ensure_dir "$data_path"
tar xzf "$backup_path" -C "$data_path" 2>&1
local code=$?
if [ $code -eq 0 ]; then
echo "Restored from ${backup_path}"
echo "Restart Domoticz with: /etc/init.d/domoticz start"
else
echo "[ERROR] Restore failed" >&2
return 1
fi
}
cmd_mesh_register() {
require_root || { echo "Root required" >&2; exit 1; }
defaults
if command -v secubox-p2p >/dev/null 2>&1; then
secubox-p2p register-service domoticz "$port" 2>&1
uci set ${CONFIG}.mesh.enabled='1'
uci commit ${CONFIG}
echo "Domoticz registered in P2P mesh on port ${port}"
else
echo "[ERROR] secubox-p2p not found — install secubox-p2p first" >&2
return 1
fi
}
cmd_service_run() {
require_root || { echo Root required >&2; exit 1; }
require_root || { echo "Root required" >&2; exit 1; }
check_prereqs || exit 1
defaults
stop_container
local docker_args="--name $CONTAINER -p ${port}:8080 -v $data_path/config:/config"
[ -d "$devices_path" ] && docker_args="$docker_args -v $devices_path:/devices"
# If MQTT enabled, pass broker info to container network
local mqtt_en=$(uci_get enabled mqtt)
if [ "${mqtt_en:-0}" = "1" ]; then
docker_args="$docker_args --add-host=mqtt-broker:$(uci_get broker mqtt || echo 127.0.0.1)"
fi
exec docker run --rm $docker_args -e TZ="$timezone" "$image"
}
cmd_service_stop() { require_root || { echo Root required >&2; exit 1; }; stop_container; }
cmd_service_stop() {
require_root || { echo "Root required" >&2; exit 1; }
stop_container
}
case "${1:-}" in
install) shift; cmd_install "$@" ;;
uninstall) shift; cmd_uninstall "$@" ;;
check) shift; cmd_check "$@" ;;
update) shift; cmd_update "$@" ;;
status) shift; cmd_status "$@" ;;
logs) shift; cmd_logs "$@" ;;
configure-mqtt) shift; cmd_configure_mqtt "$@" ;;
configure-haproxy) shift; cmd_configure_haproxy "$@" ;;
backup) shift; cmd_backup "$@" ;;
restore) shift; cmd_restore "$@" ;;
mesh-register) shift; cmd_mesh_register "$@" ;;
service-run) shift; cmd_service_run "$@" ;;
service-stop) shift; cmd_service_stop "$@" ;;
help|--help|-h|'') usage ;;

View File

@ -1523,7 +1523,7 @@
"version": "1.0.0",
"category": "iot",
"runtime": "docker",
"description": "Home automation system with support for various devices and protocols",
"description": "Home automation system with MQTT bridge, Zigbee2MQTT integration, and IoT device management",
"author": "CyberMind.fr",
"license": "GPL-3.0",
"url": "https://www.domoticz.com/",
@ -1532,34 +1532,56 @@
"home-automation",
"iot",
"smart-home",
"docker"
"docker",
"mqtt",
"zigbee",
"mesh"
],
"packages": {
"required": [
"secubox-app-domoticz",
"luci-app-domoticz",
"docker",
"dockerd"
],
"optional": [
"mosquitto-nossl",
"secubox-app-zigbee2mqtt"
]
},
"capabilities": [
"home-automation",
"iot",
"smart-home"
"smart-home",
"mqtt-bridge",
"zigbee",
"mesh-service"
],
"requirements": {
"min_ram_mb": 256,
"min_storage_mb": 100
},
"status": "stable",
"pkg_version": "1.0.0-2",
"pkg_version": "1.0.0-3",
"app_version": "1.0.0",
"changelog": {
"1.0.0-3": {
"date": "2026-02-04",
"changes": [
"LuCI dashboard with IoT integration status",
"MQTT auto-bridge for Mosquitto and Zigbee2MQTT",
"HAProxy reverse proxy integration",
"P2P mesh service registration",
"Backup and restore support",
"USB device passthrough visibility"
]
},
"1.0.0": {
"date": "2026-01-04",
"changes": [
"Added support for new devices",
"Improved automation rules",
"Enhanced device discovery"
"Initial Docker-based deployment",
"domoticzctl CLI manager",
"UCI configuration"
]
}
},