Repository navigation
YC-SM10P (RK3566): helper install and profile activation both roll back #138
Description
ha-paneld version
0.9.6
Panel hardware
Other (state in description)
What happened?
Portworld YC-SM10P - 10.1" in-wall panel, Rockchip RK3566, Android 11 userdebug,
1280x800 @160 dpi landscape, 2 GB RAM, PoE. No bundled profile matches:
ro.product.model=SM10P, ro.product.device=rk3566_r. The closest one, zx-smt156,
matches rk3566_t (an adjacent board revision) and declares su_form: none, which is
wrong for this panel.
ha-paneld 0.9.6 runs well under generic: built-in renderer, MQTT discovery, entity
filtering, light/proximity sensors, brightness, screen on/off, audio playback. Cold
start 1827 ms, warm 1417 ms, no dropped frames. I would like to contribute a profile
and hit two blockers.
BLOCKER 1 - the bundled root helper cannot be installed.
/system is unwritable and full: dm-verity is enforcing (a write appears to succeed,
the file shows up in ls, but with size 0 and no content), and free space is 4.9 MB of
1.63 GB. scripts/provision.sh therefore fails and rolls the whole install back:
/system root-helper install failed; the prior helper was preserved or restored
The panel reported: INSTALL_STEP_FAILED install_system hash_matches_hapaneld-helper_new
su is present and works (/system/xbin/su, setuid, context u:r:su:s0) and the app
reports "Root (su): available - full feature set", so the helper is not needed here.
Installing the APK directly with adb install -r -g and configuring via
POST /api/v1/config works completely.
Suggestion: when su is available and the helper cannot be written, could provisioning
continue with a warning instead of rolling back the APK install? Right now a panel
that is fully usable ends up with nothing installed.
The helper step also reports a success code as a failure, which looks like a separate
bug:
W ha-paneld/helper-migrate: bundled helper install failed: INSTALL_OK
W ha-paneld/svc: root helper migration failed; versioned helper features remain unavailable
BLOCKER 2 - every imported profile activation rolls back.
Any imported profile is staged, the service restarts itself, and then:
activation: {"state": "rolled_back", "generation": 5,
"message": "Previous activation did not report healthy; rolled back."}
This happens regardless of profile content. Following docs/profiles/testing.md I
reduced the candidate to a Stage 1 revision - identity and matching only, every
hardware fact left at Generic-safe defaults (led.autodetect, screen.brightness-zero,
su_form: android). It differs from generic only in id, display_name, soc, identity and
match. It still rolls back. Validation is clean every time: issues: [], compatible:
true, matches_this_device: true. Nothing in logcat names a failed health check - the
service restarts, reaches "frontend connected", MQTT connects, sensors start, and the
rollback notice appears on the next start. Happy to run any instrumentation that helps.
HARDWARE EVIDENCE (confirmed on the device and by the owner):
- No relays: relays=[], none physically present.
- No user LEDs: /sys/class/leds/ contains only mmc2:: (card indicator).
- No physical buttons: adc-keys declares four keys (KEY=7800000000000000) but the
enclosure has none, so evdev_buttons: [] avoids phantom entities. - No temperature/humidity sensor: cht8305: false, app reports temp=ABSENT humidity=ABSENT.
- Light and proximity work: "sensors started (light=true proximity=true)". On i2c:
4-0024:ls_em3071x and 4-0024-1:ps_em3071x - an ELAN EM3071 combined
ambient-light / IR-proximity part. - Backlight: /sys/class/backlight/backlight, max_brightness=255, bl_power present.
- Microphone present and working - worth noting for other rk809/rk817 panels: a first
capture returned all zeroes, which looks exactly like a missing part. The codec
control "Capture MIC Path" was simply set to MIC OFF. After tinymix 1 "Main Mic", a
4 s capture gave peak 886, RMS 303, 99.8% non-zero samples. A silent capture on these
panels proves nothing until that route is checked. - Speaker present and working: POST /api/v1/play with a wav URL is audible; volume
follows number._volume (verified at 70% and 100%). During playback tinycap
returns 0 frames because Android holds the device exclusively. Low-level tinyplay via
"Playback Path: SPK" produces no audible output. - No camera exposed: "Number of camera devices: 0", although 2-003c:gc2145 appears on
i2c. Recorded as a limitation rather than a capability, per docs/profiles/sharing.md.
ON THE SCREEN-OFF ROUTE - the one place where schema and device disagree. su is
present, so daemon-blpower is rejected ("daemon-blpower is reserved for sandbox-walled
profiles"). But the app does not appear to reach bl_power through su from its own
process (it falls back, and diagnostics show screen_off=brightness_zero), and the
helper cannot be installed at all (Blocker 1). So neither su-blpower nor daemon-blpower
describes what actually happens. I left brightness-zero in the Stage 1 revision.
Guidance welcome.
PROPOSED STAGE 1 PROFILE
schema: 2
id: community.yc-sm10p
version: 0.1.0
display_name: Portworld YC-SM10P
soc_class: rk3566
soc:
model: Rockchip RK3566
cpu_cores:
- architecture: Arm Cortex-A55
count: 4
metadata:
author: Community contributor
license: MIT
maturity: draft
tested_firmware:
- C06-V21.3-YC-10.1MIPI-TV101WXM-NM1-SW0.6-20231013-270 (Android 11, userdebug, rk3566_r)
limitations:
- 'Stage 1 revision: identity and matching only. Hardware facts are deliberately left at Generic-safe defaults until each control is tested separately.'
- The bundled root helper cannot be installed on this panel; dm-verity is enforcing and /system writes do not persist.
requires:
drivers:
- access.android-su
- led.autodetect
- screen.brightness-zero
match:
priority: 500
fallback: false
any:
- priority: 900
all:
- field: model
op: equals
values:
- sm10p
- field: device
op: equals
values:
- rk3566_r
platform:
su_form: android
app_can_su: true
has_recents: true
hardware:
led:
mechanism: autodetect
transfer: rk3576-four-bit
screen_off: brightness-zero
has_button_backlight: false
sensors:
cht8305: false
room_temp_offset_c: 0.0
identity:
manufacturer: Portworld
model: YC-SM10P
model_label_strategy: display-name
input:
evdev_buttons: []
cpu: {}
display: {}
provisioning:
software: {}
display: {}
packages: []
recipes: []Steps to reproduce
- Panel: Portworld YC-SM10P (SM10P / rk3566_r), Android 11 userdebug, su present,
/system full and dm-verity enforcing.
Blocker 1:
2. Run scripts/provision.sh :5555 --latest
3. The install rolls back at the root-helper step; nothing ends up installed.
4. Workaround: adb install -r -g the release APK, then configure with
POST /api/v1/config - everything works.
Blocker 2:
5. POST /api/v1/profiles/validate with the Stage 1 YAML -> issues: [], compatible: true,
matches_this_device: true.
6. POST /api/v1/profiles/import with the returned X-Profile-Preview-Token -> ok.
7. POST /api/v1/profiles/select with id + revision + expected_catalog_revision + confirm
-> 202 "Profile selection staged for restart".
8. Let the service restart itself (or reboot the panel via /api/v1/action a=reboot).
9. GET /api/v1/profiles -> active is still generic, selection back to auto, activation
state rolled_back: "Previous activation did not report healthy; rolled back."
Diagnostic dump (/diag)
ha-paneld diagnostics — 0.9.6 (build 527)
[captured] 2026-09-03T07:20:02.946+07:00 uptime=6h17m
[panel]
ha-paneld=0.9.6 (build 527)
Android=11 (API 30)
Firmware=C06-V21.3-YC-10.1MIPI-TV101WXM-NM1-SW0.6-20231013-270
Device=rockchip SM10P (rk3566_r)
CPU=4 cores · arm64-v8a · rk30board
RAM=1.9 GB total · 1012.1 MB free
Storage=31.0 GB eMMC · 24.1 GB free (data)
Display=1280×800 px · logical 160 dpi
System WebView=com.google.android.webview 113.0.5672.77
HA Companion=not installed
MQTT state=connected · TCP/IPv4 · last-ok 9s ago · last-auth 22630s ago · auth-ok · prefer IPv6
Security mode=Relaxed
Keep panel responsive=on · power locks held
Prevent idle dim=on · timeout never
Android dashboard lock=off
LED=none
Nav actions (a11y)=no
Navbar=Off
Zigbee=none
Relays=none
Network ADB=active (5555) · external — not persisted by ha-paneld
Audio playback=idle
App database=992.0 KB used · 1.5 MB on disk · schema 14
Local-state sync=22510s ago · screen →OFF (physical)
State convergence=35 channels · 0 dirty · 0 in-flight · 13 unknown · ack 434/0 · pending none
[build] fingerprint=rockchip/rk3566_r/rk3566_r:11/RD2A.211001.002/eng.root.20231013.122844:userdebug/release-keys
board=rk30sdk product=rk3566_r hardware=rk30board abis=arm64-v8a,armeabi-v7a,armeabi
[boot-security] verified=orange flash=unlocked vbmeta=unknown build=userdebug debuggable=yes
[env] selinux=0 su=true write_settings=false a11y=false daemon=true shizuku=manager_missing evdev=stopped/none ledjni=false
[display-sizing] android_base_logical_dpi=160 current_logical_dpi=160 override_dpi=none font_scale=1.0 profile_recommended_dpi=? profile_recommended_font_scale=none
[storage-health] state=healthy pressure_state=healthy usable_bytes=24158748672 total_bytes=25811746816 used_percent=6.404053765843354 database_bytes=970752 wal_bytes=41232 sidecar_bytes=32768 page_size_bytes=4096 page_count=237 freelist_count=0 schema_version=14 quick_check=ok checked_at=1788372165950 failure=none
[power-safety] state=caution keep_awake=true wake_lock=true wifi_lock_required=true wifi_lock=true prevent_idle_dim=true screen_timeout_ms=2147483647 interactive=false power_source=ac plugged_mask=1 stay_on_mask=0 stay_on_effective=false device_idle=false doze_exempt=false screen_off=brightness_zero reasons=doze_not_exempt,stay_on_disabled
[sysfs] leds=[mmc2::] backlight=[backlight] devfreq=[dmc, fde40000.npu, fde60000.gpu, fdf40000.rkvenc, fdf80200.rkvdec]
[labels] ls: /dev/ledjni: No such file or directory u:object_r:sysfs:s0 /sys/class/backlight/backlight/ u:object_r:sysfs:s0 /sys/class/leds/mmc2::/
[hardware]
inputs=[fe6e0030.pwm (event0 dmcfreq cpufreq ), rk805 pwrkey (event1 dmcfreq cpufreq ), goodix-ts (event2 dmcfreq cpufreq ), mir3da (event3 ), gsensor (event4 ), adc-keys (event5 dmcfreq cpufreq )]
i2c=[0-001c:tcs452x, 0-0020:rk809, 1-0018:bma2xx_acc, 1-0027:gs_da223, 1-0051:hym8563, 1-005d:gt9xx, 2-003c:gc2145, 4-0024:ls_em3071x, 4-0024-1:ps_em3071x, i2c-0:rk3x-i2c, i2c-1:rk3x-i2c, i2c-2:rk3x-i2c, i2c-4:rk3x-i2c, i2c-6:DesignWare HDMI]
iio=[]
thermal=[cooling_device0:thermal-cpufreq-0, cooling_device1:thermal-devfreq-0, thermal_zone0:soc-thermal, thermal_zone1:gpu-thermal, thermal_zone2:test_battery]
relays=[]
[packages] android=not installed minimal=not installed
[capabilities] Root (su)=ok | Verified app update / screenshot / display=ok | Screen brightness=degraded | Screen on/off=ok | RGB LED=none | Hardware buttons=none | Reboot / reload / launcher=ok
Home Assistant version
2026.8.3
Relevant logs
W ha-paneld/helper-migrate: bundled helper install failed: INSTALL_OK
D ha-paneld/helper: daemon not reachable (Connection refused)
W ha-paneld/svc: root helper migration failed; versioned helper features remain unavailable
I ha-paneld/svc: safe process restart requested: activating staged profile
W ha-paneld/svc: profile warning activation: Previous profile activation was rolled back after an unhealthy restart.
I ha-paneld/sensors: sensors started (light=true proximity=true temp=ABSENT humidity=ABSENT)
I ha-paneld/dashboard: frontend connected
I ha-paneld/mqtt: MQTT connected - online + state acknowledged
Activity
maxlyth commentedon Sep 6, 2026
0.9.7-rc3 is now available and includes the restart fix behind the profile rollback, so the Stage 1 profile should activate instead of returning to Generic. Could you try importing and activating the same YAML on rc3?
The helper case is separate and is not fixed by rc3. This panel has working direct
subut no supported place to keep the helper across a reboot. I am keeping that open as an installer change rather than treating the hardware as unsupported.Your hardware evidence is enough for an import-only
community.yc-sm10pprofile. I would like to use the rc3 activation result before publishing it, then test light, proximity and screen-off one capability at a time. No further probe is needed yet.vovanse commentedon Sep 7, 2026
rc3 fixes the activation. The Stage 1 profile now activates and stays active.
ha-paneld 0.9.7-rc3 (build 707) installed over 0.9.6 with adb install -r -g.
All settings survived; only auto_brightness_sensitivity changed, which looks
like a new default.
validate -> issues: [], compatible: true, matches_this_device: true
import -> "Imported Portworld YC-SM10P 0.1.0."
select -> 202 "Profile selection staged for restart."
restart -> ~15 s
result -> active: community.yc-sm10p (Portworld YC-SM10P)
activation.state "active", generation 6, message null
selection {"mode": "pinned"} (was "auto")
Still active a minute later and after the service settled. On 0.9.6 the same
YAML always ended as "rolled_back". Thank you.
CORRECTION TO MY ORIGINAL REPORT
I wrote that light and proximity work on this panel. That was wrong, and I am
sorry — I took the line "sensors started (light=true proximity=true)" as
evidence. It only reports that the app tried. What actually happens:
I SensorsHal: set active: handle = 3, enable = 1
D SensorsHal: Couldn't open /dev/psensor (No such file or directory)
E SensorsHal: PSENSOR_IOCTL_ENABLE failed (Bad file descriptor)
E SensorService: Error activating sensor 3 (Function not implemented)
D SensorsHal: Couldn't open /dev/lightsensor (No such file or directory)
E SensorsHal: LIGHTSENSOR_IOCTL_SET_RATE failed
The root cause is below Android. The kernel driver cannot reach the part at
all — it reads a chip id of zero and gives up:
gsensor_em3071x 4-0024: sensor_chip_init:ls_em3071x:devid=0x0
gsensor_em3071x 4-0024: sensor_initial:fail to init sensor
gsensor_em3071x 4-0024: sensor_chip_init:fail to init sensor
psensor_em3071x 4-0024-1: sensor_chip_init:fail to read ps_em3071x devid:0x0
Confirmed by reading the bus directly (toybox has i2cget/i2cdetect on this
panel, no extra tooling needed):
i2cget -f -y 4 0x24 0x00 -> i2c_read_byte: No such device or address
So the device tree declares 4-0024:ls_em3071x and 4-0024-1:ps_em3071x, the
driver binds to the addresses, but nothing answers there. Everything above
follows from that: no /dev/psensor or /dev/lightsensor node is created, the
HAL fails to open them, and Android refuses the app's subscriptions. dumpsys
sensorservice "Active sensors" lists only the accelerometer, and there is no
input device for either sensor:
inputs = fe6e0030.pwm (event0), rk805 pwrkey (event1), goodix-ts (event2),
mir3da (event3), gsensor (event4), adc-keys (event5)
In other words the ALS/proximity part looks unpopulated or unconnected on this
board revision, even though the device tree describes it.
Home Assistant history agrees: sensor._illuminance has 50 recorded
entries over 30 days and not one of them carries a value. My other panel
(NSPanel Pro) has 1346 entries with real readings over the same period, so
this is specific to the YC-SM10P firmware, not to ha-paneld.
So for the profile: light and proximity should be declared absent on the
YC-SM10P. No software route exists — this is a hardware/device-tree mismatch
on the panel, not something ha-paneld can work around. Sorry for sending you
down that path.
CAPABILITIES AFTER ACTIVATION
Root (su)=ok | Verified app update / screenshot / display=ok
Screen on/off=ok | Reboot / reload / launcher=ok
Screen brightness=degraded -> ok
Brightness moved to ok after granting the settings permission:
adb shell appops set io.github.maxlyth.hapaneld WRITE_SETTINGS allow
before that, [env] showed write_settings=false. Same on my other panel. Worth
mentioning in provisioning docs perhaps.
Screen off works through su_blpower and is verifiably real: with the display
asleep, /sys/class/backlight/backlight/bl_power reads 4 and brightness 0; on
wake they return to 0 and 120. Note the profile declares
screen_off: brightness-zero, yet diagnostics report screen_off=su_blpower —
the runtime seems to pick the better route on its own, which is good, but the
profile text and the reported route disagree.
API NOTE
POST /profiles/select accepts {"id", "revision", "expected_catalog_revision",
"confirm"} but rejects {"ref": {"id", "revision"}, ...} with
"invalid-profile-ref", even though /profiles returns each profile as a "ref"
object. Small asymmetry, easy to trip over.
Also: repeated imports accumulate. The catalog now holds four copies of
community.yc-sm10p from earlier attempts, each with its own revision hash.
UPDATED PROFILE — 0.1.1
Based on the above I revised the Stage 1 draft and verified it on the panel:
validate -> issues: [], compatible: true, matches_this_device: true
import -> "Imported Portworld YC-SM10P 0.1.1."
select -> 202, restart, activation.state "active", generation 7
capabilities afterwards: Root (su)=ok | Screen brightness=ok |
Screen on/off=ok | Reboot / reload / launcher=ok
Two substantive changes from 0.1.0:
hardware.screen_off: brightness-zero -> su-blpower
with requires.drivers updated to screen.su-blpower. The runtime already
chose su_blpower on its own, and it is real: asleep, bl_power reads 4;
awake it returns to 0. Brightness control is unaffected — setting 200
then 40 writes straight through to /sys/class/backlight/backlight/
brightness with bl_power staying 0, and the value survives a sleep cycle.
hardware.led.mechanism: autodetect -> none
/sys/class/leds holds only mmc2:: (card activity), so there is nothing
to autodetect.
Light and proximity stay undeclared, which now reflects the hardware rather
than caution. The limitations list records the evidence.
HELPER
Unchanged, as you expected — /system is full and dm-verity is enforcing, so
there is still nowhere to keep it. Direct su continues to cover everything I
need, so this panel is fully usable without the helper.
maxlyth commentedon Sep 9, 2026
That is the result I wanted before publishing, and the detail you went to makes it usable.
I am taking two things from your 0.1.1 over my draft: su-blpower as the screen-off route, and led mechanism none. Both are better evidence than I had.
No need to apologise for the light and proximity line. A message reading "sensors started" when it only means the app tried is my wording problem, not your misreading, and your i2c probe settles it either way. They will be declared absent.
The WRITE_SETTINGS grant is the third report this week from different hardware, so I am treating it as a provisioning gap rather than a per-device quirk.
The profile and runtime disagreeing about the screen-off route, the ref object being rejected by /profiles/select, and the catalogue accumulating duplicate imports are all real. I will split them into their own issues so they do not get lost in this thread.
maxlyth commentedon Sep 9, 2026
Correction to one line above. I said the WRITE_SETTINGS grant looked like a provisioning gap. It is not. The installer grants that app-op as one of its steps, warns with the manual Settings path when a vendor build refuses it, and re-reads the result at the end, and it is in the permissions table in the provisioning docs.
Installing with adb install -r -g skips all of that, and -g covers runtime permissions rather than app-ops, which is why it stayed unset across your upgrade. So the answer to "worth mentioning in provisioning docs perhaps" is that it is already there, and you found the one route that goes around it.
Nothing to fix, and I should have checked before saying otherwise. The catalogue and API items above are unaffected.
feat: report declared vs selected screen-off route
fix(sensors): stop advertising a light sensor that never activates (#138
fix: collapse repeated imports of one profile into a single catalogue…
maxlyth commentedon Sep 27, 2026
A quick round-up now that 0.9.8 is out, since everything from this thread except the helper has shipped.
In 0.9.7: select, activate and delete accept the nested ref that the profile list hands out, diagnostics show the screen-off route your profile declares next to the one the panel actually used, and the import-only community.yc-sm10p profile is published, with su-blpower for screen off, no LED, and no light or proximity sensor.
In 0.9.8: re-importing a profile replaces it in the list instead of adding another copy, with earlier revisions behind Show superseded revisions, and a light sensor that never starts no longer turns up as an illuminance sensor.
Keeping the helper across a reboot on a panel like yours, with direct su but nowhere persistent to put it, is still open, so I am leaving the issue open for that.
fix: collapse repeated imports of one profile into a single catalogue…