Skip to content

tplink-kasa-kc110: ship vendor OV2735 libsns (fixes no video), ultimate majestic - #108

Merged
openipc-ai merged 2 commits into
OpenIPC:masterfrom
moontwister:kc110-ci-matrix
Aug 27, 2026
Merged

tplink-kasa-kc110: ship vendor OV2735 libsns (fixes no video), ultimate majestic#108
openipc-ai merged 2 commits into
OpenIPC:masterfrom
moontwister:kc110-ci-matrix

Conversation

@moontwister

@moontwister moontwister commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Two changes to the KC110 device profile added in #99, so the device produces video once CI builds it. The built image was hardware-verified on a KC110 (streams 1080p out-of-the-box).

The CI-registration half of this PR is dropped: the matrix has been derived from the tree since #120, and the KC110's NOT_BUILT opt-out is removed by #132 instead. BR2_PACKAGE_JSONFILTER=y needed no change here — #128 had already removed it from this defconfig, so the rebase inherited that.

1. Ship the vendor OV2735 libsns — fixes no video

OpenIPC's opensdk libsns_ov2735.so does not drive this OV2735: the sensor i2c init aborts (hi_i2c_wait_txfifo_notfull / hi_i2c_abortprocess) and the sensor never streams — MIPI detects no valid frame, VENC stays idle, /image.jpg hangs.

This ships the vendor libsns_ov2735.so (from the device's stock firmware, same provenance as the rest of the HiSilicon stack) as a device-overlay payload — the documented pattern for a sensor lib the SoC osdrv doesn't correctly provide. It loads cleanly against OpenIPC's libisp/lib_hiae, so no other files are needed, and it is scoped to this device's overlay (cannot affect other boards).

Hardware-proven by a bidirectional, single-variable swap on a live KC110: opensdk libsns → no video; vendor libsns → instant 1080p — on both firmware HEAD and the 2026-06-17 release.

2. Select the ultimate majestic variant (consistency)

The defconfig sets BR2_OPENIPC_VARIANT="ultimate" but omitted BR2_OPENIPC_MAJESTIC, so it fell back to the lite default (general/Config.in). This aligns the device with its declared variant, matching the two other devices that set it (both hi3516ev300_ultimate_*).

Device builds clean (rootfs 6440 KB / 8192 KB NOR).

@moontwister moontwister changed the title master.yml: register hi3518ev200_ultimate_tplink-kasa-kc110 for CI tplink-kasa-kc110: register for CI and select the ultimate majestic variant Jun 27, 2026
@moontwister moontwister changed the title tplink-kasa-kc110: register for CI and select the ultimate majestic variant tplink-kasa-kc110: register for CI, ship vendor OV2735 libsns (fix no video), ultimate majestic Jun 27, 2026
@openipc-ai

Copy link
Copy Markdown
Contributor

Thanks for this, and sorry it sat. Three changes are bundled here and they've diverged in status.

The CI registration — the master.yml matrix line — is what makes this branch conflict. Since #120 the matrix is derived from the tree rather than listed, and devices that existed but were in no matrix at the time (the KC110 among them) were frozen into a NOT_BUILT opt-out in .github/scripts/ci-matrix.py. I've opened #132 to remove the KC110 and the Tapo TC70 v3 from that set, which is this half of your PR done the way the selector now wants it. Because a change to ci-matrix.py can't narrow, #132 runs the full matrix, so the KC110 gets its first-ever build there.

The other two changes are untouched by any of that and still wanted:

  • BR2_OPENIPC_MAJESTIC="ultimate" — consistent with the only two other devices that set it, both hi3516ev300_ultimate_*.
  • the vendor libsns_ov2735.so overlay for the no-video bug. This is the part I can't verify from here, and it's the interesting one.

Could you drop the master.yml hunk and rebase on master? That leaves a focused PR, and PR CI will then build hi3518ev200_ultimate_tplink-kasa-kc110 narrowed to just that device — so we'd see the overlay actually go through a build.

One thing while you're in there: please also drop BR2_PACKAGE_JSONFILTER=y if it's still selected — #128 removed it from all 97 defconfigs after firmware/#2304.

openipc-ai added a commit that referenced this pull request Aug 27, 2026
Step 6 of "Adding a new device" still says to add `- <device>` to the
matrix in .github/workflows/master.yml, and calls that matrix "the *only*
build registry". Neither has been true since #120 moved the matrix into
.github/scripts/ci-matrix.py, where it is derived from the tree rather
than listed. master.yml now has no device list at all.

This is not a hypothetical staleness. Two of the pull requests open right
now do exactly what step 6 says: #111 (Tapo TC70 v3) and #108 (KC110)
each append a line to a block that no longer exists, so both are merge
conflicts rather than the one-line changes they were written as. Their
authors did the documented thing.

So step 6 is now the opposite instruction -- there is nothing to add, and
adding it is the mistake. It also names NOT_BUILT, since that is the one
list a contributor could reasonably go looking for, and says to leave it
alone.

Two adjacent claims went stale with the same change and are fixed here:
the master.yml bullet described a cron-and-dispatch workflow with no
pull_request trigger, and nothing in the file mentioned ci-matrix.py at
all -- including that --self-test runs in the Select devices job and will
fail a PR that puts the tree and the selector out of step. Step 8 no
longer says "locally" as though that were the only way a device gets
built.
openipc-ai added a commit that referenced this pull request Aug 27, 2026
)

Step 6 of "Adding a new device" still said to add `- <device>` to the matrix in
.github/workflows/master.yml, and called that matrix "the *only* build registry".
Neither has been true since #120 moved the matrix into .github/scripts/ci-matrix.py,
where it is derived from the tree rather than listed. master.yml has no device list
at all.

Not a hypothetical staleness: #111 (Tapo TC70 v3) and #108 (KC110) each append a line
to a block that no longer exists, so both are merge conflicts rather than the one-line
changes they were written as. Their authors did the documented thing.

So step 6 is now the opposite instruction -- there is nothing to add, and adding it is
the mistake. It also names NOT_BUILT, since that is the one list a contributor could
reasonably go looking for, and says to leave it alone.

Two adjacent claims went stale with the same change: the master.yml bullet described a
cron-and-dispatch workflow with no pull_request trigger, and nothing mentioned
ci-matrix.py at all -- including that --self-test runs in the Select devices job and
will fail a PR that puts the tree and the selector out of step.

A second correction, caught by Qodo in review: "opening the PR is what gets the device
built" holds only for a non-draft PR. classify() returns needs_build=False for a draft
and self_test() asserts it; master.yml lists ready_for_review in its triggers precisely
because a PR opened as a draft would otherwise never build once marked ready. Left as
written, a contributor could open a draft, see no build, and read that as the device
being fine. The ci:full label is documented for the same reason -- it is the other
contributor-facing lever over the matrix.
moontwister and others added 2 commits August 27, 2026 20:09
The device defconfig set BR2_OPENIPC_VARIANT="ultimate" but omitted
BR2_OPENIPC_MAJESTIC, so it fell back to the "lite" default
(general/Config.in). All stock *_ultimate firmware defconfigs set
BR2_OPENIPC_MAJESTIC="ultimate"; this aligns the device with its
declared variant.

Note: this is a variant-consistency fix, NOT a fix for the no-video
problem. On-hardware testing (hi3518ev200 + OV2735) showed the device
produces no video with BOTH the lite and the ultimate majestic — the
sensor i2c writes abort, so the OV2735 never streams. The majestic
variant is therefore not the cause; that issue is separate and not
addressed here.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
OpenIPC's opensdk libsns_ov2735.so does not drive the OV2735 on this
board: the sensor i2c init aborts and the sensor never streams (MIPI
detects no valid frame, VENC never encodes, /image.jpg hangs). This was
isolated and hardware-proven by a bidirectional, single-variable swap on
the live camera: with opensdk's libsns -> no video; swapping in the
vendor libsns -> instant 1080p (verified against both firmware HEAD and
the 2026-06-17 release, so it is the sole cause, independent of the
kernel/opensdk version).

Ship the vendor libsns_ov2735.so as a device-overlay payload (the
documented pattern for a sensor lib the SoC osdrv does not correctly
provide). It loads cleanly against OpenIPC's libisp / lib_hiae, so no
other files are needed. Scoped to this device's overlay -> cannot affect
other boards.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
openipc-ai added a commit that referenced this pull request Aug 27, 2026
Both devices have had a complete devices/<dir>/ in this tree for a long time and had
never once been built. #120 froze that state rather than changing it -- it put the 7
defconfigs that were in no master.yml matrix into NOT_BUILT so that a device falling out
of CI would be a test failure instead of a silent skip. Freezing was right for a change
whose job was to not alter what gets built; it was never meant to be permanent for
devices whose only problem is that nobody added the matrix line.

Two contributors did try to add that line. #111 (Tapo TC70 v3, July) and #108 (KC110,
June) both append to the device list in master.yml, which is where the registry lived
when they were written. It does not live there any more -- the matrix is read off the
tree -- so both PRs are merge conflicts now, and the devices they asked for are exactly
the two entries removed here. This is their CI half, landed the way the selector wants
it. #108 also carries a BR2_OPENIPC_MAJESTIC="ultimate" line and a vendor
libsns_ov2735.so for the no-video bug; those are unaffected and stay with that PR.

The two self-test cases that used t31_lite_tp-link-tapo-tc70-v3 as their example of an
unbuilt device move to t31_lite_xiaomi-mjsxj05hl, which is still in NOT_BUILT. The
overlay case also switches to a path that exists, since the device it now names has no
etc/inittab.

Neither device had ever been through a build, so this PR was where we found out. That
was affordable exactly once: a change to ci-matrix.py cannot narrow -- it is what does
the narrowing -- so this ran the full matrix and proved both in the same run. Both are
green:

    Firmware (hi3518ev200_ultimate_tplink-kasa-kc110)   SUCCESS
    Firmware (t31_lite_tp-link-tapo-tc70-v3)            SUCCESS
@moontwister moontwister changed the title tplink-kasa-kc110: register for CI, ship vendor OV2735 libsns (fix no video), ultimate majestic tplink-kasa-kc110: ship vendor OV2735 libsns (fixes no video), ultimate majestic Aug 27, 2026
@openipc-ai

Copy link
Copy Markdown
Contributor

Thanks — this is exactly what was asked for. The master.yml hunk is gone, it rebases cleanly, and splitting it into two commits with real messages makes it reviewable. The CI half landed separately in #132 (9df259c), so the KC110 is out of NOT_BUILT and building on master now.

What I could verify statically, against master:

  • BR2_OPENIPC_MAJESTIC="ultimate" matches the only other devices that set it, both hi3516ev300_ultimate_*. Consistent.
  • The blob is the right shapeELF 32-bit LSB shared object, ARM, EABI5, which is what the arm-openipc-linux-musleabi toolchain wants.
  • It survives the rootfs prune. hi3518ev200_ultimate.list strips /etc/sensors/ov2735_i2c_1080p.ini but not /usr/lib/sensors/libsns_ov2735.so, so the overlay copy makes it into the image. Worth stating because that list is exactly where a new overlay file goes to die.
  • jsonfilter: ignore my earlier note — this defconfig never selected it, so there's nothing to drop. My mistake.

One thing worth recording in the commit message rather than changing:

hisilicon-osdrv-hi3516cv200 already installs its own libsns_ov2735.so (line 77 of the .mk), so this overlay overrides it rather than filling a gap. They are genuinely different builds — 23076 bytes here vs 17988 upstream — which is consistent with the KC110 needing the MIPI variant while the osdrv ships the DVP/i2c one, matching the ov2735_mipi_1080p.ini and patched load_hisilicon this device already carries.

That is the right call for the fix, but it does pin this device to the vendor blob permanently: if firmware ever updates its own libsns_ov2735.so, the KC110 will keep using yours and nobody will notice. Since a binary is not something a future maintainer can diff, could you add a line to the commit message saying where the blob came from — which stock TP-Link firmware image and version you pulled it out of? That is the piece of context that cannot be recovered later.

To actually build it, a maintainer needs to approve the workflow run. The run is sitting at action_required (the first-time-contributor gate), so no build has happened on this branch yet. Once approved it narrows to just hi3518ev200_ultimate_tplink-kasa-kc110, so it is one device's worth of runner time.

Nothing here blocks merging on my side beyond seeing it build.

@openipc-ai

Copy link
Copy Markdown
Contributor

Heads-up on a false green, and a bit of noise incoming — nothing you need to do.

I approved the workflow run, and it came back green, but it did not actually build anything:

ci-matrix: self-test ok (107 devices, 15 smoke, 39 cases)
ci-matrix: 0/107 devices (needs_build=False) --- nothing that reaches a build

That is a timing artifact, not a problem with your branch. The run was created at 18:10, and #132 — the PR that takes the KC110 out of NOT_BUILT — merged at 18:24. So the selector evaluated the pre-#132 tree, where this device was still opted out of CI, and correctly narrowed to nothing. Approving a run later does not recompute its base; it just releases what was already queued. Note the 107 devices: master is at 110 now.

Reopening the PR to force a fresh evaluation against current master (reopened is one of the workflow's triggers). You will get a close/reopen notification — please ignore it, the branch is untouched.

@openipc-ai openipc-ai closed this Aug 27, 2026
@openipc-ai openipc-ai reopened this Aug 27, 2026
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Aug 27, 2026

Copy link
Copy Markdown

PR Summary by Qodo

Restore KC110 video with vendor OV2735 library and ultimate Majestic

🐞 Bug fix ⚙️ Configuration changes 🕐 10-20 Minutes

Grey Divider

AI Description

• Package KC110's vendor OV2735 sensor library to restore reliable 1080p video.
• Select ultimate Majestic so runtime capabilities match the declared firmware variant.
Diagram

graph TD
  CFG["KC110 defconfig"] -->|selects| BUILD["Buildroot image"] -->|produces| FW["KC110 firmware"] -->|runs| MAJ["Ultimate Majestic"] -->|serves| VIDEO["1080p video"]
  LIB["Vendor OV2735 lib"] -->|device overlay| BUILD
  FW -->|initializes| SENSOR["OV2735 sensor"] -->|frames| VIDEO
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Repair the OpenSDK OV2735 driver
  • ➕ Avoids shipping a proprietary binary payload
  • ➕ Could fix other boards using the same sensor and SoC stack
  • ➖ Requires deeper hardware debugging or reverse engineering
  • ➖ Broadens regression risk beyond the KC110
  • ➖ Delays a fix already isolated and validated on hardware

Recommendation: Use the device-scoped vendor library as the immediate fix because bidirectional hardware testing isolates it as the working component and the overlay prevents impact on other boards. An upstream OpenSDK driver repair remains the preferable long-term replacement if equivalent initialization can be implemented and validated.

Files changed (2) +1 / -0 · 1 not counted

Bug fix (1)
libsns_ov2735.soPackage the working vendor OV2735 sensor library not counted

Package the working vendor OV2735 sensor library

• Adds the stock KC110 sensor library as a device-only overlay payload, replacing the incompatible OpenSDK implementation at runtime. The vendor library initializes the sensor successfully and restores hardware-verified 1080p streaming.

devices/hi3518ev200_ultimate_tplink-kasa-kc110/general/overlay/usr/lib/sensors/libsns_ov2735.so

Other (1) +1 / -0
hi3518ev200_ultimate_tplink-kasa-kc110_defconfigSelect the ultimate Majestic runtime variant +1/-0

Select the ultimate Majestic runtime variant

• Sets 'BR2_OPENIPC_MAJESTIC="ultimate"' so the KC110 no longer inherits the lite default. This aligns the packaged Majestic runtime with the device's existing ultimate firmware declaration.

devices/hi3518ev200_ultimate_tplink-kasa-kc110/br-ext-chip-hisilicon/configs/hi3518ev200_ultimate_tplink-kasa-kc110_defconfig

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Aug 27, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

Tip of the day
💡 Did you know, you can ask Qodo to dismiss a finding you disagree with, with your reason on record

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Previous reviews

Review updated until commit c6a15e9 ⚖️ Balanced

Results up to commit c6a15e9


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

Qodo Logo

@openipc-ai

Copy link
Copy Markdown
Contributor

One more close/reopen notification from me, sorry — last one. Explaining so the churn on your PR makes sense.

My first attempt to re-trigger this raced GitHub: when I reopened at 18:58, refs/pull/108/merge was still parented on 82ab2e7, one commit before #132 took the KC110 out of NOT_BUILT. So the run faithfully checked out a tree where this device is opted out and correctly built nothing.

I then assumed re-running the workflow would pick up the newer base. It does not — a re-run pins the merge commit computed when the run was first created, so attempt 3 checked out the identical 81d4d99 and reached the identical decision. That was my mistake, not a CI bug.

The merge ref has since been recomputed to dc5c2fc, parented on current master 9df259c, where the KC110 is in the build set. Reopening once more, which creates a genuinely new run pinned to that merge commit.

Your branch has not been touched at any point.

@openipc-ai openipc-ai closed this Aug 27, 2026
@openipc-ai openipc-ai reopened this Aug 27, 2026
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit c6a15e9

@openipc-ai

Copy link
Copy Markdown
Contributor

Built, and properly this time. Run 33106540798 checked out the right base:

HEAD is now at dc5c2fc  Merge c6a15e92b... into 9df259cb6...   <- current master
ci-matrix: self-test ok (110 devices, 15 smoke, 39 cases)
ci-matrix: 1/110 devices (needs_build=True) --- narrowed to the affected devices
Firmware (hi3518ev200_ultimate_tplink-kasa-kc110)   SUCCESS

Fit is a non-issue on this board:

- uImage:          [1776KB/2048KB]
- rootfs.squashfs: [6276KB/8192KB]

and no entry in hi3518ev200_ultimate.list reported "matched no file", so the exclude list is not stale against the tree your overlay produces.

Note the earlier Firmware SKIPPED entries still visible in the check list — those are the two runs against the pre-#132 base and can be ignored; the one that matters is the named device job above.

So: the defconfig change and the overlay compile and fit. What CI cannot tell us is whether the vendor blob actually fixes the no-video symptom — that needs the camera. If you have flashed this image on the KC110 and have video, say so on the PR and that is good enough for me.

Still useful whenever you get to it: which stock TP-Link firmware image and version the .so came from, in the commit message. It is the one thing about a binary that cannot be recovered later.

@openipc-ai
openipc-ai merged commit 2ca0796 into OpenIPC:master Aug 27, 2026
23 checks passed
@openipc-ai

Copy link
Copy Markdown
Contributor

Merged as 2ca0796 — and an apology for the runaround at the end.

I told you "nothing here blocks merging on my side beyond seeing it build", it built, and I then asked for hardware confirmation and the blob's provenance before merging. That was moving the goalposts after you had already done everything asked, and it was the wrong call. The bar I stated was the bar.

The provenance question stands only as a nice-to-have: if you happen to remember which stock TP-Link image the .so came from, drop it in a comment here and it will be in the history for whoever next has to reason about that binary. Not needed for anything.

Thanks for coming back to a PR that had sat since June, and for splitting it cleanly when asked.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants