External integration - Unify network

But that’s already the principle of the « Discovery » page!

So why not just increase the limit?

Because even at 100 devices… it’s unreadable ^^ So at 950… I’ll let you imagine

And without a search field… humhum ^^ it’s possible though (the browser’s CTRL+F works) but in terms of user-friendliness… ^^

If you have another suggestion, I’d be happy to hear it :sweat_smile:

I’m increasing the limit, and I’m adding a search filter!

Perfect ^^ Thanks a lot ^^

So @Terdious, we need to agree on how we work. I have absolutely no problem with you making PRs, but I didn’t create this integration to give you more work!

I’ll leave it up to you to tell me; I’m open to anything!!

Ouioui!! No worries (and work never bothers me, it benefits us all ^^

I just take a lot of time to write you the reply message, to make it as well crafted and understandable as possible using AI (much better presentation). So it’s long, but I read and correct everything, normally everything is clear, and in the end you’ll see it’s not so complicated ^^

Every little External Integration becomes an independent Gladys micro-project ^^

Hop :

Damn… that leaves some margin there ^^

I tested it, the search works well!

It’s merged, it will be in the next Gladys release (today)

I’m so weak …

:innocent:

Yeees welcome!!

:face_with_peeking_eye: :wink: :joy: Normal, it’s the beginning, we’ve all been there!

But yes, absolutely avoid this: main is the branch that everyone uses. A breaking change, and it’s your users who get hit with it.


The Simple Rule

Every change (unless you’re 100% sure about something very simple) must be made on a separate branch, which you push as a tagged image :dev, or :dev-tartempion for a specific test with someone.

Concretely, your cycle becomes:

main  ──►  feature branch  ──►  (test image :dev)  ──►  back to main

And that’s about it. In the command line, it’s literally:

git checkout main
git pull
git checkout -b fix-ip-gateway     # your feature branch
# ... you work, you commit ...
git push -u origin fix-ip-gateway

Two immediate advantages:

  • if something breaks for someone, you revert by deleting/canceling one branch, not by untangling 15 commits mixed in main;
  • you can have multiple projects in parallel without them stepping on each other.

PRs: Not Mandatory, But Very Useful

Note: PRs are not mandatory. You can perfectly do main → feature branch → main alone, without ever opening a PR.

It’s especially useful:

  • when someone outside wants to propose something (my case);
  • when you want to share progress/preparation before releasing it.

Personally, I work a lot with PRs even on my own repos, because:

  • you have a real, readable history, with the why of each change;
  • you can comment directly in the code;
  • you can have long-term topics without having to remember which branch it was — all the context is in the PR.

What You’ll Actually Need to Do with a PR

Well, good news: you already have everything you need in your repo :sweat_smile:

First, the most important: a PR changes NOTHING for you until you click.
As long as you haven’t pressed the green button, your main is intact, your :latest image is intact, your users see nothing. Zero risk. And you can close a PR without merging it, without any justification. Even if it’s better with, I won’t hide it ^^

Then, in order:

1. The CI checks the code for you — it’s already set up
Your .github/workflows/ci.yml already triggers on: pull_request. For each PR, it automatically runs:

  • npm run format:check (Prettier)
  • npm run lint (ESLint)
  • npm test

So you don’t have anything to review to know if it’s broken: you look at the bottom of the PR, green check = it passes, red cross = it doesn’t. That’s all.

2. You can ask your AI for a review
You give it the PR link and ask it to review and comment directly in it. I’ll see its comments and I’ll fix them. That’s where the back-and-forth happens, without you having to write a line.

3. You build a test image — this is also already set up
Your .github/workflows/build.yml already has a workflow_dispatch with an image-tag field that defaults to the branch name, and most importantly, it doesn’t touch :latest. So:

Actions tab → Build workflow → Run workflow button → you choose the branch → Run

et you get ghcr.io/guim31/gladys-integration-unifi:<nom-de-la-branche> that you pull into your Docker to test in real life. Your users on :latest don’t see anything pass.

(Small detail: your build.yml only triggers automatically on v* tags, i.e., your releases. The manual trigger above is therefore the right path to test a branch.)

4. You merge (or not)
If your tests are OK: big green button « Merge pull request » at the bottom of the PR, then « Confirm merge ». Two clicks. You can also ask your AI to do it.
If it doesn’t suit you: you comment, or you close. No problem.

In short, you never have to read my code if you don’t want to. You look at the green checkmark, you test the image, you click.


A point on the fork => And therefore the PRs that appear to you

How we organize ourselves concretely (and you keep ALL the rights)

I specify, because it’s important: I don’t ask for any rights on your repo. I do exactly what I do on the Gladys repo — I fork, I work on my fork, I propose a PR to you. I can neither push to you nor merge. You are the only one who can press the button. This is the standard open-source way, and it’s great like that.

And for testing, no need for you to build anything: I deliver the image to you at the same time as the PR.

The sequence

  1. I work on a branch of my fork.
  2. I launch the build at my place — your build.yml works as is in a fork, it calculates the image with ghcr.io/${GITHUB_REPOSITORY,,} and never overwrites latest. For example, it gives me ghcr.io/terdious/gladys-integration-unifi:fix-ip-gateway.
  3. I make this package public at my place.
  4. I open the PR at your place, and I put the image address directly in the description, with the manifest to copy-paste.
  5. You install this image in your Gladys, you test it, and you tell me.
  6. If it’s good: green button. Otherwise: you comment, or you close.

So you have nothing to build, nothing to configure, and nothing to uninstall.

How you install my image (2 fields to fill in)

In Gladys: Integrations → Install from GitHub → « Developer mode: install from a Docker image »

  • Docker Image field → you paste the address I give you in the PR;
  • Manifest (JSON, optional) field → you paste the JSON I give you right below.

And that’s it. Two copy-pastes.

Two or three things to know

It installs SIDE BY SIDE with your current version, you don’t break anything.
Gladys builds the selector differently depending on the installation mode: ext-guim31-gladys-integration-unifi for your normal install, ext-dev-unifi-network for an install by image. Two different selectors = the two integrations coexist quietly. You keep your production running, you test on the side, and when you’re done, you just uninstall the test one.

Why do I have to give you the manifest to paste?
Normally, Gladys can read it alone in the labels of the image (the label io.gladysassistant.manifest). But your Dockerfile doesn’t set any, and your build.yml doesn’t pass any either, so the installation would fail on a MANIFEST_NOT_FOUND. Hence the manual copy-paste — no big deal, that’s exactly what the optional field is for.

So I propose this as your very first PR: adding this label to the image. It’s 2 lines, it doesn’t touch any functional code, and after that, anyone (you first) will be able to install a test image by pasting just its name, without a manifest. It improves your own dev comfort for all the following times — and it lets you see the PR mechanism from start to finish with zero risk. Ideal for getting your hands on it :slight_smile:

A point of attention for testing
Since the two integrations run in parallel, they discover the same devices. However, in Gladys, the selector of a device is unique at the global level. Therefore:

  • to check what a PR changes (the IP parameters, the port features that appear or not, the names) → the discovery screen of the test instance is more than enough, you don’t add anything, no risk;
  • to actually control a PoE port from the test instance → you must first delete the devices concerned on the production side, otherwise you will get an error when adding them. Nothing is broken, just an error message in the card, but it’s better to know.

And in the long run

When you’re comfortable, the extra comfort is to create a dev branch for yourself:

git checkout main
git checkout -b dev
git push -u origin dev

You merge the PRs as you go (this never publishes anything, latest doesn’t move), you build your :dev image from Actions → Build → Run workflow → dev branch, you test several changes at once, and you only merge to main when you’re happy. But it’s not necessary to start.


On duplicated devices

Well, I’m going to reassure you: it’s not Gemini’s fault, and your code was probably good. :sweat_smile:

What you saw is not a problem with the naming of your features, it’s the behavior of Gladys’ discovery screen: on these small cards, Gladys displays the category of the feature, not its name.

The proof is in my own captures from the previous post:

  • on the Dream Machine Pro card, you read Presence / Throughput / Throughput — while in your gateway.js these features are actually called Status, WAN Upload Speed, and WAN Download Speed. Two identical Throughput on the screen, two distinct names in the code;
  • and above all, on the « PoE Switch: SW-CAMPING-02 » card, you still read 4 × Switch. In other words: the duplication did not solve the problem you were trying to solve — the ports remain indistinguishable on this screen, separated or not :sweat_smile:

While in the JSON of the discovered devices (my first capture), your names are perfect: Port 1 (SW-MAISON-01 / Port 19). They are well there, they are well built.

30-second test if you want to check: add a switch to Gladys, then go add the ports on the dashboard, you will have the correct names. You will see the real names (Port 1 (…), Port 3 (…), etc.), and you will find them again in the feature selectors when you build a scene.

So if you agree, we can merge without fear: one switch = one device, presence + ports together, everything remains identifiable. The real gain is the number of devices and consistency :wink:


That’s it, tell me what you prefer on the fork vs collaborator, and which point you want to start with. I suggest starting with the local IP / public IPs of the gateway: it’s the most autonomous, it touches a single file, and it will give you a first PR « for the road » to see the mechanism in real life without risk :slight_smile:

Thanks a lot for this VERY complete message! :slight_smile:

As I already explained: I’m not a developer, I have no training in that area. This project exists because AI allows me to build things today that I would never have been able to write myself. So when you say that I never have to read your code if I don’t want to… that’s great ^^ I wouldn’t be able to judge it anyway. And that’s fine: I much prefer to trust you on the substance and focus on what I know how to do, test at home for real.

So the fork + PR system is perfect for me. That way I’ll see each
change one by one, with the reason written next to it.

What you explain about « as long as you don’t click, nothing moves » reassures me. I had the impression that a PR was already a foot in the door. Now I understand that I keep control from start to finish, and that changes everything in my approach to the thing.

For the order, I follow you 100%:

  1. the PR of the label in the Dockerfile, so that I can see the entire
    mechanism on a zero-risk item;
  2. then the local IP / public IPs of the gateway.

About the duplicated equipment: thanks for the details and especially for telling me that it wasn’t necessarily my fault. I hadn’t understood at all that the discovery screen displayed the category and not the name of the feature — so I had « fixed » something that wasn’t broken. I’ll assume you’re right: we merge, one switch = one piece of equipment. I can try to do this part in a PR on my side to get my hands on it!

And I note the rule « one modification = one branch », I’ll also do that for my
own modifications, Claude is still a great friend for these things :stuck_out_tongue:

I’ll have silly questions along the way, I prefer to warn you :slight_smile:

Thanks for taking all this time!!!

Small step on my side: I merged the switches and made my first PR! I use the « I » but we all know who’s behind it :wink:

One piece of hardware = one device now.

It’s merged into main but I haven’t made a release.

Anyway, I’m ready for your PR whenever you want :slight_smile:

To add my two cents, I tested version 1.5.2 on my end and the retrieval of elements works fine :slight_smile: