Control QUBO smart plugs and air purifiers from Home Assistant over your own MQTT broker, without the QUBO cloud.
This is an independent community integration. It is not made, supported or endorsed by QUBO or Hero Electronix.
- Automatic Device Discovery - Automatically detects QUBO devices on your network via MQTT
- 100% Local Control - No cloud dependency, complete privacy
- Real-time Switch Control - Turn devices on/off instantly
- Energy Monitoring - Track power consumption, voltage, current, and total energy
- Automatic Updates - Energy data refreshed every 60 seconds
- Fan Control - Turn on/off with speed levels (Low, Medium, High)
- Preset Modes - Auto and Manual modes
- Air Quality Monitoring - Real-time PM2.5 readings (updated every ~3 seconds)
- Filter Life Tracking - Monitor remaining filter life in hours (auto-refreshed hourly)
- Purifier Card Compatible - Works with popular purifier-card for beautiful UI
- Device Integration - All entities grouped under a single device in Home Assistant
- Auto Device Type Detection - Automatically identifies Smart Plugs (HSP) and Air Purifiers (HPH)
- Home Assistant 2025.3 or newer, with the MQTT integration configured
- Local MQTT broker (e.g., Mosquitto) with TLS/SSL enabled on port 8883
- Router or DNS server with custom DNS entry support
- All network clients must use your DNS server (router DNS settings)
- QUBO Smart Plug and/or Air Purifier
Important: QUBO devices connect to
mqtt.platform.quboworld.comon port 8883 using TLS/SSL encryption. Your local MQTT broker must be configured with TLS certificates to accept these connections. Simple DNS redirection without TLS will not work.
To enable local control, you need to redirect the QUBO device's cloud MQTT connection to your local broker. This requires two key components:
- TLS-enabled MQTT broker listening on port 8883
- DNS override to redirect the cloud hostname to your local broker
First, set up your MQTT broker with TLS support. Here's a complete Mosquitto configuration:
# Create directory for certificates
sudo mkdir -p /etc/mosquitto/certs
cd /etc/mosquitto/certs
# Generate CA key and certificate
openssl genrsa -out ca.key 2048
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt \
-subj "/CN=MQTT CA"
# Generate server key and certificate signing request
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr \
-subj "/CN=mqtt.platform.quboworld.com"
# Create extensions file for SAN (Subject Alternative Name)
cat > server.ext << EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = mqtt.platform.quboworld.com
DNS.2 = localhost
IP.1 = 192.168.1.68
EOF
# Sign the server certificate (replace IP with your broker's IP)
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out server.crt -days 3650 -extfile server.ext
# Set permissions
sudo chown mosquitto:mosquitto /etc/mosquitto/certs/*
sudo chmod 600 /etc/mosquitto/certs/*.keyCreate or edit /etc/mosquitto/conf.d/qubo.conf:
# Standard MQTT (optional, for local testing)
listener 1883 localhost
allow_anonymous true
# TLS MQTT for QUBO devices (required)
listener 8883
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
cafile /etc/mosquitto/certs/ca.crt
# Allow connections without client certificates
require_certificate false
# Authentication (optional but recommended)
allow_anonymous true
# Or use password file:
# password_file /etc/mosquitto/passwd
# allow_anonymous false
# Logging (helpful for debugging)
log_type all
log_dest file /var/log/mosquitto/mosquitto.logRestart Mosquitto:
sudo systemctl restart mosquittoVerify TLS is working:
# Test TLS connection locally
mosquitto_sub -h localhost -p 8883 --cafile /etc/mosquitto/certs/ca.crt \
-t '/monitor/#' -v
# Or without certificate verification (for testing)
mosquitto_sub -h localhost -p 8883 --insecure \
-t '/monitor/#' -vConfigure your DNS to resolve mqtt.platform.quboworld.com to your local MQTT broker's IP address.
Critical: Your router must be configured to use your DNS server (Pi-hole, AdGuard Home, etc.) as the primary DNS for ALL clients. If devices use external DNS directly (8.8.8.8, etc.), the redirect won't work.
- Go to Local DNS → DNS Records
- Add entry:
- Domain:
mqtt.platform.quboworld.com - IP Address: Your MQTT broker IP (e.g.,
192.168.1.68)
- Domain:
- Ensure your router's DHCP assigns Pi-hole as the DNS server
- Go to Filters → DNS rewrites
- Add rewrite:
- Domain:
mqtt.platform.quboworld.com - Answer: Your MQTT broker IP
- Domain:
- Ensure router uses AdGuard as DNS server
Some routers support custom DNS entries directly:
- Access router admin panel
- Find DNS or Host Override settings
- Add:
mqtt.platform.quboworld.com→192.168.1.68
# From a device on your network
nslookup mqtt.platform.quboworld.com
# Should return your local MQTT broker IP, NOT the cloud IP
# Cloud IPs to watch for (these mean DNS redirect isn't working):
# 65.1.150.122 (AWS Mumbai)
# 13.x.x.x, 52.x.x.x (other AWS IPs)After DNS and TLS are configured:
- Unplug the QUBO device from power
- Wait 10-15 seconds
- Plug it back in
- The device will resolve the hostname via your DNS and connect to your local broker
Monitor for device heartbeat on your local broker:
# Using TLS (recommended)
mosquitto_sub -h YOUR_MQTT_BROKER -p 8883 \
--cafile /etc/mosquitto/certs/ca.crt \
-t '/monitor/+/+/heartbeat' -v
# Without certificate verification (testing only)
mosquitto_sub -h YOUR_MQTT_BROKER -p 8883 --insecure \
-t '/monitor/+/+/heartbeat' -v
# Or if you have a local non-TLS listener for HA
mosquitto_sub -h YOUR_MQTT_BROKER -p 1883 \
-t '/monitor/+/+/heartbeat' -vYou should see heartbeat messages within 30-60 seconds of power cycling.
- Open HACS in Home Assistant.
- Search for QUBO Local Control, open it, and click Download.
- Restart Home Assistant.
Not listed yet? Open HACS → ⋮ → Custom repositories, add https://github.com/dtechterminal/qubo-local-control as an Integration, then search again.
Download the source code of the latest release, copy its custom_components/qubo_local folder into your Home Assistant config/custom_components/ folder, and restart Home Assistant.
The integration listens for the heartbeat messages QUBO devices send to your broker, and tells smart plugs (HSP_) and air purifiers (HPH_) apart from their device ID.
- Go to Settings → Devices & Services → + Add Integration.
- Search for QUBO Local Control.
- Choose Find devices automatically. It listens for 30 seconds.
- Pick your device and click Submit.
Devices you have already added are not listed again. Heartbeats from the QUBO phone app are ignored. If nothing is heard, the integration opens the manual form instead.
If automatic discovery doesn't work, you can manually configure the integration:
Subscribe to MQTT heartbeat topic to see your device information:
# Using TLS (port 8883)
mosquitto_sub -h YOUR_MQTT_BROKER -p 8883 --insecure -t '/monitor/+/+/heartbeat' -v
# Or with certificate verification
mosquitto_sub -h YOUR_MQTT_BROKER -p 8883 --cafile /etc/mosquitto/certs/ca.crt \
-t '/monitor/+/+/heartbeat' -v
# Or on local non-TLS listener (if configured)
mosquitto_sub -h YOUR_MQTT_BROKER -p 1883 -t '/monitor/+/+/heartbeat' -vThe JSON payload will contain:
{
"devices": {
"deviceUUID": "your-device-uuid",
"entityUUID": "your-entity-uuid",
"unitUUID": "your-unit-uuid",
"userUUID": "your-user-uuid",
"srcDeviceId": "HSP_AA:BB:CC:DD:EE:FF"
}
}Device Type Identification:
HSP_prefix = Smart PlugHPH_prefix = Air Purifier
- Go to Settings → Devices & Services
- Click + Add Integration
- Search for "QUBO Local Control"
- Select Enter device details
- Enter the device information:
- Device UUID
- Entity UUID
- Unit UUID
- Handle Name (userUUID)
- Device Name (optional, friendly name)
- Device MAC Address (optional)
- Device Type (Smart Plug or Air Purifier)
- Click Submit
| Entity | Type | Description |
|---|---|---|
| Switch | switch |
Controls the power state |
| Power | sensor |
Current power consumption (W) |
| Voltage | sensor |
Current voltage (V) |
| Current | sensor |
Current draw (A) |
| Energy | sensor |
Total energy consumption (kWh) |
| Entity | Type | Description |
|---|---|---|
| Fan | fan |
On/Off, Speed (Low/Medium/High), Mode (Auto/Manual) |
| PM2.5 | sensor |
Air quality reading (µg/m³) |
| Filter Life | sensor |
Remaining filter life (hours) |
When a device disconnects from your broker, its last-will heartbeat reports it offline and its entities show as unavailable until it sends data again.
The fan entity exposes additional attributes for dashboard cards:
| Attribute | Description |
|---|---|
percentage |
Current speed as percentage (0-100) |
preset_mode |
Current mode (Auto/Manual) |
preset_modes |
Available modes list |
pm25 |
Current PM2.5 reading (µg/m³) |
aqi |
Alias for pm25 (for card compatibility) |
filter_life_remaining |
Filter hours remaining |
speed |
Current speed level (1/2/3) |
speed_list |
Available speed levels |
/control/{unit_uuid}/{device_uuid}/lcSwitchControl- Switch control/control/{unit_uuid}/{device_uuid}/meteringRefresh- Energy monitoring refresh
/monitor/{unit_uuid}/{device_uuid}/lcSwitchControl- Switch state updates/monitor/{unit_uuid}/{device_uuid}/plugMetering- Energy data updates/monitor/{unit_uuid}/{device_uuid}/heartbeat- Device heartbeat
/control/{unit_uuid}/{device_uuid}/lcSwitchControl- Power control/control/{unit_uuid}/{device_uuid}/fanSpeedControl- Fan speed (1/2/3)/control/{unit_uuid}/{device_uuid}/fanControlMode- Mode (auto/manual)/control/{unit_uuid}/{device_uuid}/aqiRefresh- AQI data refresh/control/{unit_uuid}/{device_uuid}/filterReset- Filter status request
/monitor/{unit_uuid}/{device_uuid}/lcSwitchControl- Power state updates/monitor/{unit_uuid}/{device_uuid}/fanSpeedControl- Speed state updates/monitor/{unit_uuid}/{device_uuid}/fanControlMode- Mode state updates/monitor/{unit_uuid}/{device_uuid}/aqiStatus- PM2.5 readings/monitor/{unit_uuid}/{device_uuid}/filterReset- Filter life remaining/monitor/{unit_uuid}/{device_uuid}/heartbeat- Device heartbeat
This integration is compatible with purifier-card for a beautiful air purifier UI.
Installation:
- Install purifier-card via HACS or manually
- Add the card to your dashboard
Example Configuration:
type: custom:purifier-card
entity: fan.qubo_air_purifier
show_name: true
show_state: true
show_toolbar: true
# AQI display (reads from fan entity attribute)
aqi:
attribute: aqi
unit: 'µg/m³'
# Stats display
stats:
- attribute: pm25
unit: 'µg/m³'
subtitle: PM2.5
- attribute: filter_life_remaining
unit: 'hours'
subtitle: Filter Life
# Quick shortcuts
shortcuts:
- name: Low
icon: mdi:fan-speed-1
percentage: 33
- name: Medium
icon: mdi:fan-speed-2
percentage: 66
- name: High
icon: mdi:fan-speed-3
percentage: 100
- name: Auto
icon: mdi:brightness-auto
preset_mode: Auto
- name: Manual
icon: mdi:hand-back-right
preset_mode: ManualYou can also use the built-in fan card:
type: fan
entity: fan.qubo_air_purifier
name: Air PurifierThis is the most common issue. Follow these steps to diagnose:
Check that the QUBO hostname resolves to your local IP:
# From a computer on the same network
nslookup mqtt.platform.quboworld.com
# Expected: Your local MQTT broker IP (e.g., 192.168.1.68)
# Problem: Cloud IP like 65.1.150.122, 13.x.x.x, 52.x.x.xIf DNS returns cloud IP:
- Ensure your router uses your DNS server (Pi-hole/AdGuard) as primary DNS
- Check that the DNS server has the correct entry
- Some routers/devices bypass local DNS - check for hardcoded DNS settings
Test your TLS setup:
# Test TLS connection to your broker
openssl s_client -connect YOUR_BROKER_IP:8883 -servername mqtt.platform.quboworld.com
# Check certificate details
openssl s_client -connect YOUR_BROKER_IP:8883 </dev/null 2>/dev/null | openssl x509 -text -nooutCommon TLS issues:
- Certificate CN must match
mqtt.platform.quboworld.com - SAN (Subject Alternative Name) should include the hostname
- Certificate must not be expired
# View Mosquitto logs
sudo tail -f /var/log/mosquitto/mosquitto.log
# Look for:
# - "New connection from [IP]" - device is reaching your broker
# - "Socket error" or "TLS error" - certificate/TLS issues
# - "Client disconnected" - connection but then dropUse tcpdump to see if the device is reaching your broker:
# Monitor port 8883 traffic
sudo tcpdump -i any port 8883 -n
# You should see traffic from the QUBO device IP to your broker
# If traffic goes to AWS IPs (65.1.x.x, 13.x.x.x), DNS redirect isn't working# Subscribe to all topics on TLS port
mosquitto_sub -h YOUR_BROKER -p 8883 --insecure -t '#' -v
# Or with certificate
mosquitto_sub -h YOUR_BROKER -p 8883 --cafile /etc/mosquitto/certs/ca.crt -t '#' -vIf DNS and TLS are correct but no heartbeats appear:
- Power cycle the device - Unplug for 10+ seconds, then reconnect
- Check Mosquitto is listening on 8883:
sudo netstat -tlnp | grep mosquitto # Should show: 0.0.0.0:8883
- Verify firewall allows port 8883:
sudo ufw status # or your firewall tool
Some QUBO firmware versions may implement certificate pinning, which validates the server certificate against a known certificate. If you suspect this:
- Check device firmware version in the QUBO app
- Try downgrading firmware if possible
- The device may require the exact certificate chain from the cloud broker
Note: Certificate pinning is a security feature. If the device uses it, local control may not be possible without firmware modification.
If energy sensors are not updating:
- Check that MQTT broker is accessible
- Verify device is connected to local MQTT broker (check heartbeats)
- Check Home Assistant logs for errors:
Settings → System → Logs - Ensure the
plugMeteringtopic is being published
If PM2.5 sensor is not updating:
- Verify device is connected to local MQTT broker
- Check if heartbeat messages are being received
- The purifier reports AQI every ~3 seconds when running
- Try sending an
aqiRefreshcommand manually
- Verify MQTT topics are correct
- Check device UUIDs match your device
- Monitor MQTT traffic to see if commands are being sent:
mosquitto_sub -h YOUR_MQTT_BROKER -p 8883 --insecure -t '/control/#' -v - Verify Home Assistant MQTT integration is configured for TLS
Ensure Home Assistant's MQTT integration is configured to connect to your broker:
# configuration.yaml (if not using UI)
mqtt:
broker: YOUR_BROKER_IP
port: 1883 # Use non-TLS port for HA, or 8883 with certificate config
# If using TLS for HA connection:
# port: 8883
# certificate: /ssl/ca.crtMost setups use a non-TLS local listener (port 1883) for Home Assistant while the TLS listener (port 8883) handles QUBO devices.
Each device can only be added once. To reconfigure:
- Go to Settings → Devices & Services
- Find "QUBO Local Control"
- Click the three dots menu → Delete
- Add the integration again
custom_components/qubo_local/
├── __init__.py # Setup: waits for MQTT, starts the device, forwards platforms
├── protocol.py # Topics, command payloads and message parsing (no Home Assistant imports)
├── device.py # One subscription per device, latest values, availability, refresh timers
├── entity.py # Base entity that follows its device's reported values
├── config_flow.py # Discovery and manual setup
├── fan.py # Air purifier
├── sensor.py # Energy, PM2.5 and filter-life sensors
├── switch.py # Smart plug relay
├── brand/ # Integration icon (see docs/branding.md)
└── translations/en.json
Run the tests and linter:
uv run --with pytest pytest -q
uv run --with ruff ruff check custom_components testsThe tests use payload shapes recorded from a real plug and purifier, with synthetic IDs.
{
"command": {
"devices": {
"deviceUUID": "device-uuid",
"entityUUID": "entity-uuid",
"services": {
"lcSwitchControl": {
"attributes": {
"power": "on"
},
"instanceId": 0
}
}
}
}
}{
"command": {
"devices": {
"deviceUUID": "device-uuid",
"entityUUID": "entity-uuid",
"services": {
"fanSpeedControl": {
"attributes": {
"speed": "3"
},
"instanceId": 0
}
}
}
}
}Speed values: 1 (Low), 2 (Medium), 3 (High)
{
"command": {
"devices": {
"deviceUUID": "device-uuid",
"entityUUID": "entity-uuid",
"services": {
"fanControlMode": {
"attributes": {
"state": "auto"
},
"instanceId": 0
}
}
}
}
}Mode values: auto, manual
{
"command": {
"devices": {
"deviceUUID": "device-uuid",
"handleName": "user-uuid",
"services": {
"meteringRefresh": {
"attributes": {
"duration": "60"
},
"instanceId": 0
}
}
}
}
}{
"devices": {
"services": {
"aqiStatus": {
"events": {
"stateChanged": {
"PM25": "5"
}
},
"instanceId": "0"
}
}
}
}{
"devices": {
"services": {
"filterReset": {
"events": {
"stateChanged": {
"timeRemaining": "8997"
}
},
"instanceId": "0"
}
}
}
}timeRemaining is in hours.
MIT License - See LICENSE file for details
Contributions are welcome! Please open an issue or submit a pull request.
Developed by @dtechterminal
- Entities show as unavailable while the device reports itself offline, instead of keeping stale states
- One MQTT subscription per device; subscriptions are now removed when an entry is reloaded or deleted
- Discovery shows a progress screen, ignores the QUBO app's heartbeats and already-added devices, and reads plug heartbeats that contain numbers with leading zeros
- Setup waits for MQTT to be ready instead of failing
- Refreshed integration icon, shown locally on Home Assistant 2026.3 and newer
- Added tests and CI (tests, hassfest, HACS validation)
- Improved documentation with detailed TLS/SSL setup instructions
- Added comprehensive Mosquitto TLS configuration guide
- Added troubleshooting section for DNS and TLS connection issues
- Clarified that QUBO devices use port 8883 with TLS (not plain MQTT)
- Added Pi-hole, AdGuard Home, and router DNS configuration examples
- Fixed fan state not updating correctly after power toggle
- Added automatic hourly filter status refresh
- Fixed energy sensor state class for proper long-term statistics
- Added Air Purifier support with fan control, PM2.5 sensor, and filter life tracking
- Added purifier-card compatibility with extra state attributes
- Added automatic device discovery via MQTT heartbeat messages
- Improved device type auto-detection (Smart Plug vs Air Purifier)
- Initial release with Smart Plug support
- Switch control and energy monitoring
For issues and feature requests, please use the GitHub issue tracker.