Skip to content

YC-SM10P (RK3566): helper install and profile activation both roll back #138

Open

Description

@vovanse

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

  1. 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

  1. self-assigned this
    on Sep 6, 2026
  2. added
    questionFurther information is requested
    and removed
    bugSomething isn't working
    on Sep 6, 2026
  3. maxlyth commented on Sep 6, 2026

    @maxlyth
    Collaborator

    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 su but 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-sm10p profile. 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.

  4. vovanse commented on Sep 7, 2026

    @vovanse
    Author

    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.

    schema: 2
    id: community.yc-sm10p
    version: 0.1.1
    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:
        - 'Screen off verified on hardware through su-blpower: with the display asleep /sys/class/backlight/backlight/bl_power reads 4 and brightness 0, and both return to 0 and 120 on wake.'
        - 'No ambient-light or proximity sensor: the device tree declares 4-0024:ls_em3071x and 4-0024-1:ps_em3071x, but the part does not answer. The kernel driver reads a chip id of zero (sensor_chip_init:fail to read ps_em3071x devid:0x0) and a direct i2cget on 4/0x24 returns ENXIO, so no /dev node, no input device and no Android sensor route exist. Left undeclared deliberately.'
        - 'No user LEDs: /sys/class/leds contains only mmc2:: (card activity indicator).'
        - 'No relays and no physical buttons: adc-keys declares four keys but the enclosure has none, so evdev_buttons stays empty to avoid phantom entities.'
        - The bundled root helper cannot be installed on this panel; dm-verity is enforcing and /system writes do not persist. Direct su covers every capability the panel needs.
    requires:
      drivers:
        - access.android-su
        - screen.su-blpower
    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: none
      screen_off: su-blpower
      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: []

    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.

  5. maxlyth commented on Sep 9, 2026

    @maxlyth
    Collaborator

    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.

  6. added
    bugSomething isn't working
    in progressActively being worked on
    and removed
    questionFurther information is requested
    on Sep 9, 2026
  7. maxlyth commented on Sep 9, 2026

    @maxlyth
    Collaborator

    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.

  8. added
    questionFurther information is requested
    enhancementNew feature or request
    backlogAdded to future development queue with no assigned release version
    and removed
    in progressActively being worked on
    bugSomething isn't working
    on Sep 27, 2026
  9. maxlyth commented on Sep 27, 2026

    @maxlyth
    Collaborator

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

backlogAdded to future development queue with no assigned release versionenhancementNew feature or requestquestionFurther information is requested

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions