Skip to content

LiTinOveWeedle changes#21

Open
willglynn wants to merge 15 commits intomainfrom
dev
Open

LiTinOveWeedle changes#21
willglynn wants to merge 15 commits intomainfrom
dev

Conversation

@willglynn
Copy link
Owner

I took @litinoveweedle's changeset from #19, rewrote git history to make the following changes, and opened this PR to better review and further discuss them:

  • Collapse the myriad build.yml changes into one commit, since it was lots of noise
  • Revert version changes, since this repo has not released such versions
  • Eliminate edition = 2025, since there is no such Rust edition

* implemented TCP keep alives

* reconnect logic implementation

* updated README for new  features

* read code de-duplication into function
* implemented TCP keep alives

* refactored TCP keepalive patch

* updated Cargo.lock

* fix keepalive retries compilation

* compilation fixes

* fix unused code

* fix arguments comments

* updated Help and README

* initial reconnect logic implementation

* compilation fixes, reformated

* updated README for new reconnect feature
unified buffer read
added reconnect logging

* reconnect logic de-duplication into function

* implement retry mechanism on connection open fail

* README typo fix

* improved cli arguments dependencies

* arg dependencies
Set reconnect default timeout to 60
…weedle#4)

* fix invalid NodeTableResponse struct

* added infrastructure event in observe mode - to output in JSON gateway and node details (addresses, barcodes, versions etc.)

* added persistent storage

* Updated README to reflect implementation
@willglynn willglynn mentioned this pull request Oct 30, 2025
@willglynn
Copy link
Owner Author

@litinoveweedle What was your motivation for changing PowerReportEvent's Gateway to be a GatewayID and Node to be a NodeID? I thought it would be better to include MAC addresses and barcodes if known.

@litinoveweedle
Copy link

Doing my changes in your PR doesn't sound nice to me - the one thing you can give me is credit for my work and in your PR it will be gone/lost in the Github merge. But sure, license permits that, so you are free to do that. ;-o

@litinoveweedle What was your motivation for changing PowerReportEvent's Gateway to be a GatewayID and Node to be a NodeID? I thought it would be better to include MAC addresses and barcodes if known

This can be reverted, but I do not see is it as a perfect way - it will only work completely/as expected/correctly after ~12-24hrs when during the night Node Table Response messages are received. Also the correlation is build in the taptap - you can't change it or implement it to your needs. When used with any log parsers and or data stores (Logstash/Fluentd + Elastic) you would like those components to be the one to correlate, index etc - those are perfect for the usage. I wanted taptap to work in KISS design principles, like some generic Linux GNU tool - do one thing, but do it well. Not to be jack of all trades poorly.

In my case, when I run taptap and I need to immediately start producing enumerated (identified by serials) output - but without data in the persistent file I need to be able to temporary enumerate serials defined by users to the panels/tigo optimizers, even before receiving any serials from taptap. So I implemented this temporary defined serial to 'some' PV node, till the proper identification is received during the night. Also same is valid for the re-installation of the HA addon, when already capture persistent data will be lost. And I can guarantee there will be tons of the user issues, that I installed your addon, and it doesn't work, with my response it is not a bug but feature, for the first time i might need one day to start working.

And again I can implement same feature in the taptap, or half in the taptap and half in the higher layer, but to me, the best design is to implement complete PV node it to serial correlation and logic outside of the taptap, so anyone can decide and implement what is best to them. Whats supports this is, that no one would be using taptap just on its own, but always inside of something - ELK, MQTT bridge etc. and this is than nice place to implement complete correlation for your use case - someone might prefer temporary correlation, other might not.

@willglynn
Copy link
Owner Author

Doing my changes in your PR doesn't sound nice to me - the one thing you can give me is credit for my work and in your PR it will be gone/lost in the Github merge. But sure, license permits that, so you are free to do that. ;-o

@litinoveweedle The commits in this branch still list you as the author regardless of who opened the PR. Given your unfamiliarity with Rust and the volume of changes I was about to request, I chose to open a PR so that I can make those changes myself on top of yours – ultimately merging your features, preserving your authorship, and sparing your Copilot tokens – and so that I can push my changes somewhere we can both discuss them before merging.

@litinoveweedle What was your motivation for changing PowerReportEvent's Gateway to be a GatewayID and Node to be a NodeID? I thought it would be better to include MAC addresses and barcodes if known

This can be reverted, but I do not see is it as a perfect way - it will only work completely/as expected/correctly after ~12-24hrs when during the night Node Table Response messages are received. Also the correlation is build in the taptap - you can't change it or implement it to your needs. When used with any log parsers and or data stores (Logstash/Fluentd + Elastic) you would like those components to be the one to correlate, index etc - those are perfect for the usage. I wanted taptap to work in KISS design principles, like some generic Linux GNU tool - do one thing, but do it well. Not to be jack of all trades poorly.

In my case, when I run taptap and I need to immediately start producing enumerated (identified by serials) output - but without data in the persistent file I need to be able to temporary enumerate serials defined by users to the panels/tigo optimizers, even before receiving any serials from taptap. So I implemented this temporary defined serial to 'some' PV node, till the proper identification is received during the night. Also same is valid for the re-installation of the HA addon, when already capture persistent data will be lost. And I can guarantee there will be tons of the user issues, that I installed your addon, and it doesn't work, with my response it is not a bug but feature, for the first time i might need one day to start working.

And again I can implement same feature in the taptap, or half in the taptap and half in the higher layer, but to me, the best design is to implement complete PV node it to serial correlation and logic outside of the taptap, so anyone can decide and implement what is best to them. Whats supports this is, that no one would be using taptap just on its own, but always inside of something - ELK, MQTT bridge etc. and this is than nice place to implement complete correlation for your use case - someone might prefer temporary correlation, other might not.

Right, that all makes sense. These exact concerns motivated my design of these data structures:

#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct Gateway {
    /// The gateway's link layer ID.
    ///
    /// This value can change over time and is duplicated between different systems, but it is
    /// always present.
    pub id: gateway::link::GatewayID,

    /// The gateway's hardware address.
    ///
    /// This value is permanent and globally unique, but it is not always known.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub address: Option<pv::LongAddress>,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct Node {
    /// The node's ID.
    ///
    /// This value can change over time and is duplicated between different gateways, but it is
    /// always present.
    pub id: pv::NodeID,

    /// The node's hardware address.
    ///
    /// This value is permanent and globally unique, but it is not always known.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub address: Option<pv::LongAddress>,

    /// The node's barcode.
    ///
    /// This value is permanent and globally unique, but it is not always known.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub barcode: Option<Barcode>,
}

Gateway can always include an id, and if we've seen one, it may sometimes include an address. Node can always include an id, and if we've seen one, it may sometimes include address and barcode.

taptap is guaranteed to handle gateway identification frames and node tables before any outside application sees them. My thought was that taptap should record this information in its PersistentState and collate it for all consuming applications so that consuming applications don't need to reimplement that with their own logic and state. taptap can always tell consuming applications the best information, so it should be responsible for doing that.

@litinoveweedle
Copy link

Regarding the authorship as far as I know, the GitHub will not add in this way the author's name to the contributors lists. At least that is my experience on my projects where I am trying to exactly avoid that situation. I understand my rust level is not anywhere near to yours, and you shall probably add copilot there as well, but you did say previously that you are not gonna implement any features or fix bugs anymore, only accept PR, so I did my best, as I did not saw line of Rust programmers waiting to do that job.

Regarding that enumeration, as I said, do whatever you want, but one feature which sometimes works immediately, sometimes only after day, dependant also on the persistent - state file switch .... That will not be straightforward to users.

@willglynn
Copy link
Owner Author

Regarding the authorship as far as I know, the GitHub will not add in this way the author's name to the contributors lists. At least that is my experience on my projects where I am trying to exactly avoid that situation.

Gotcha. GitHub's docs indicate that commit author email is used to drive the contributors list. My expectation is that you will be listed as a GitHub contributor once this branch or any other branch containing commits you authored lands in main. If that turns out not to be the case, I would be happy to address that with a followup PR.

I understand my rust level is not anywhere near to yours, and you shall probably add copilot there as well, but you did say previously that you are not gonna implement any features or fix bugs anymore, only accept PR, so I did my best, as I did not saw line of Rust programmers waiting to do that job.

Of course! I appreciate your effort, and I want this repo to solve your problems, which is why I'm not insisting that you change a bunch of stuff on your own. I think we had a miscommunication though. My specific message was:

I am happy to maintain this project – to preserve its functionality, to review code submissions, to publish updates – but do not currently have the time or imperative to sit down and develop new features. By all means, open PRs with the expectation that they could be merged and released.

If you opened one PR per feature, we could have discussed/iterated/merged them here and cut releases as you went. That's not how we got here though, and rather than ask you to disentangle all your work, I figured it'd be better for me to start from where you are, to understand your motivations, to propose a derivative of your work to merge upstream, and to discuss as we go.

Regarding that enumeration, as I said, do whatever you want, but one feature which sometimes works immediately, sometimes only after day, dependant also on the persistent - state file switch .... That will not be straightforward to users.

I agree it's not straightforward but I also don't see how it's avoidable. Neither taptap nor anyone else can know node MACs/barcodes until the CCA asks for them. I think the best we can do is to avoid requiring that other applications reimplement this logic and state handling over and over again.

How are you using infrastructure reports? It seems like the primary use would be to store them in the receiving application and then use them to interpret node IDs (which is what I think we can avoid by emitting Node instead). Are there other uses?

@litinoveweedle
Copy link

litinoveweedle commented Oct 30, 2025

OK, fine, thank you, lets just discuss the functional stuff.

I agree it's not straightforward but I also don't see how it's avoidable. Neither taptap nor anyone else can know node MACs/barcodes until the CCA asks for them. I think the best we can do is to avoid requiring that other applications reimplement this logic and state handling over and over again.

How are you using infrastructure reports? It seems like the primary use would be to store them in the receiving application and then use them to interpret node IDs (which is what I think we can avoid by emitting Node instead). Are there other uses?

I do use those to interpret Node id and gateway ID into address, serial, versions etc. In the configuration of the Home Assistant addon user defines user friendly name for every PV node/panel and serial (in the same way as in the Tigo app/cloud). When taptap is executed there are two options - it will either immediately fire infrastructure event from the existing persistent file and based on that I can update friendly-name -> serial relation in the HA, or if this is not yet known HA addon will create temporary random mapping between friendly-name -> serial and correct it later, when real infrastructure event is fired. So yes, it can happen that for the first 12-24 hours the mapping will not be correct, but at least the addon will work and display data, although panels migh get mixed. (very often not, as ID are sequential)

Having the information about power and infrastructure in two separate event/messages is perfectly fine - the event structure is well defined, and information are split in the way any relational database would like them normalized. What you propose is to put everything in power report, even there is always some higher layer over the taptap which would do that correlation much better - especially when serial, address, versions tend to change very rarely, and there is no reason why to emits those for every power event. Such duplication is unnecessary - when any infrastructure information is received (much more rarely) then dedicated infrastructure event is fired. I do not need to parse every power report and see, that serial does or doesn't change (as it almost never does).

  • Power report event (often, only during day) -> power output might change -> parse it -> store it in the power report table/index/MQTT topic
  • Infrastructure report event (rarely, only during night) -> infrastructure might data change -> parse it -> store it in the infrastructure table/index/MQTT topic

Do you see why I prefer separation into two independent events? Especially when there is always some layer above taptap which by nature handle any data parsing/enhancement/storing/indexing very well - as it is its primary functionality.

Put into power report all those redundant rarely changing fields (addresses, versions, serials) data and it will be emitted thousands time, always same data, same gateway address and version for every node, same barcode for given node, again and again. To me this is completely wrong. What is your argument against having it split? That user needs to do the correlation? User will not be reading taptap output, some application will. And it can correlate its output if needed - or do anything else - but that is up to the given use case.

@litinoveweedle
Copy link

I would maybe also suggest to complete implementation of the Topology Report in the observer.rs Those messages are received during the day and it is my understanding, that those also include PV node addresses which could be converted to the barcodes/serial. This would increase number of messages which can init/update serial numbers.

@litinoveweedle
Copy link

Hello, may I ask what is your plan on merging this #21 and pushing changes for #20 ? I did postponed the release of the HA taptap addon until this is resolved, but if you plan to postpone this I would need to backport your changes into my fork. Can you please let me know? Thank you.

@willglynn
Copy link
Owner Author

Of course. I spent the last couple days preparing for travel this week and haven't been able to respond to the software topics. I'll be away through Friday but expect to find time to continue discussing them here while I'm away.

I think we could get this branch in a state where I'd be happy to merge and cut a release this coming weekend.

FWIW I do not intend to unilaterally merge this branch or to release changes derived from yours without coordinating with you. You made these changes to better serve your users, and while I don't want to upstream your changes as-is, I also don't want to harm your users.

@litinoveweedle
Copy link

Thank you for your reply. I would also prefer to incorporate all required changes into your upstream. I think that we have currently single open topic: where to put the addresses/serials/or any other detailed information.

I would like to keep the current 'infrastructure event' as it is. It could also be later expanded by other information received by taptap (i.e. nodes mesh topology etc). Combining all those data together in the power event doesn't seems to be right.

Taking my architect hat on, I would still keep infrastructure data separated as I don't see taptap as end-to-end tool for monitoring, but rather as the Tigo data access layer with higher functions separated in other software in the best implementation of the Unix philosophy:

  1. Make each program do one thing well. To do a new job, build afresh rather than complicate old programs by adding new "features".
  2. Expect the output of every program to become the input to another, as yet unknown, program. Don't clutter output with extraneous information. Avoid stringently columnar or binary input formats. Don't insist on interactive input.
  3. ....

The first two points exactly match our discussion so far. I know I am lousy programmer but I am IT architect by profession, and I would strongly prefer to just follow SW architecture proven by years.

@litinoveweedle
Copy link

I would maybe also suggest to complete implementation of the Topology Report in the observer.rs Those messages are received during the day and it is my understanding, that those also include PV node addresses which could be converted to the barcodes/serial. This would increase number of messages which can init/update serial numbers.

Something like this could/should work....

    fn topology_report(
        &mut self,
        gateway_id: GatewayID,
        pv_node_id: NodeID,
        topology_report: &TopologyReport,
    ) {
        // Update the gateway_node_tables with the node information from topology report
        let node_table = self
            .persistent_state
            .gateway_node_tables
            .entry(gateway_id)
            .or_default();
        
        node_table.0.insert(pv_node_id, topology_report.long_address);
        
        // Write the updated persistent state to disk
        self.write_persistent_state();
    }

@litinoveweedle
Copy link

Last comment. I started to backport your changes in this PR back to my fork so I can release it ASAP. It seems that you had need to rename persistent_file into state_file in your modifications of my original PR. But it is IMHO also wrong. This file has to do nothing with the state of the taptap process. State files on the Linux reflect state of the process. Not its persistent data. State files are NOT data files.

On the other hand file to store persistent data of the process could be called persistent-file, persistent-data or data-file, etc.

The funny thing is, that my MQTT wrapper had ALREADY state_file option - where it writes exactly the information about its process state. So if not changed I will have two states files options even only one is used correctly and the other not. Could you please propose some other name to avoid further breaking of my other work?

@willglynn
Copy link
Owner Author

It seems like there's three main topics here:

  1. What is and is not in scope for taptap observe
  2. Which identifiers are output on power report events
  3. Which other event(s) are provided to support consuming applications

These are interrelated, but I'll try to articulate my thoughts in order.

Scope

taptap peek-*'s job is to faithfully and statelessly decode the protocol at various layers. By contrast, taptap observe's job is to build a model of the system it's observing in order to provide more useful output. "Do one thing and do it well" requires taptap observe to intelligently track and apply state for the benefit of consuming applications.

For example, the protocol has no notion of realtime clocks. Instead, each gateway autonomously increments a slot clock counter which it communicates to the CCA. taptap observe can, should, and does build a model mapping a counter value to a timestamp, and then use that model to emit normal timestamps instead of counter values, just so that no one else has to think about this. It completely encapulates this protocol detail, which is desirable for all consuming applications.

I believe addressing warrants a similar approach. Gateway IDs and node IDs are always available in the protocol and taptap 0.1.1 emits them. However, the (gateway ID, node ID) tuple does not uniquely identify the same node over time. In fact the gateway enumeration process unconditionally resets gateway IDs. Your CCA might put your gateway back to the same ID each time it enumerates, but I've seen it not do this in a multi-gateway setup, and there's no guarantee this behavior will remain unchanged with future CCA firmware. Moreover, there isn't just "the protocol" – I'm describing the current "mesh" protocol, but we already know that there is an older "star" protocol which works differently, and who knows what's coming down the pipe in the future. In my view, gateway IDs and (mesh) node IDs are protocol details which taptap observe should attempt to encapsulate, just like the slot clock.

Output identifiers

The UNIX philosphy produced no end of UNIX tools which repeat portions of their output when such repetition is meaningful. Consider two versions of find /, one which prints:

/
/bin
/bin/cat
/bin/echo
/bin/sh
…

And one which prints:

descending into: bin
file: cat
file: echo
file: sh
…

The second version is clearly less usable than the first because it requires the consuming application to keep track of values find already knows. It is better for find to always print the full path of the files it finds than for find to print the output of readdir() and to require callers to track find's recursion.

Turning to time series databases like InfluxDB and Prometheus, these systems all expect label repetition, accepting input data like:

power_report,barcode="XXXX",gateway_id="A",mac="YYYY",node_id="B" input_v=45.25,output_v=45,… 1762137595000000
tigo_voltage{barcode="XXX",gateway_id="A",mac="YYYY",node_id="B",point="input"} 45.25 1762137595000
tigo_voltage{barcode="XXX",gateway_id="A",mac="YYYY",node_id="B",point="output"} 45 1762137595000

These systems partition data into a two level hierarchy: timestamped data points are densely packed into labeled collections of such points. Labels like the four IDs above are part of the collection and are inherently deduplicated. It's cheap to add data point, it's cheap to have many labels, it's cheap to query across combinations of various labels, but it's difficult or impossible to do operations analogous to SQL JOINs or UPDATEs.

In reply to:

Put into power report all those redundant rarely changing fields (addresses, versions, serials) data and it will be emitted thousands time, always same data, same gateway address and version for every node, same barcode for given node, again and again. To me this is completely wrong. What is your argument against having it split? That user needs to do the correlation? User will not be reading taptap output, some application will. And it can correlate its output if needed - or do anything else - but that is up to the given use case.

It's much easier to remove identifiers which aren't needed than to add identifiers which are needed. If taptap observe events contain all applicable identifiers, a consuming application could easily and statelessly translate events into the forms above, like the actual version of find. If taptap observe events contain only a single identifier, the consuming application must recover its state in order to do so, like the hypothetical alternative version of find.

I do not understand why you see repeated identifiers as a negative here. If you're storing taptap observe's output, the repeated JSON structure carries much more overhead, and both the JSON structure and the repeated identifiers would compress really well. Not repeating identifiers instead repeats complexity, which is a much bigger cost, especially since this protocol is apparently still evolving.

Other events

I assumed you had a purpose for that event beyond just decoding power reports, which is why I asked what it was. Showing a table of hardware in a dashboard makes sense. I agree you should have an event for that, I agree it makes sense to emit this event as facts are learned, and I agree it makes sense to emit this event on startup based on persistent data.

The most general thing taptap observe could produce there might be a "discovery" event: here's the hardware we know about as that information evolves. In the spirit of containing complexity, I want to be careful with schema design; it would be nice if adding "star" support later didn't necessarily break this event's structure.

It also makes sense that you'd want to retrospectively assign a MAC address/barcode to a previously unidentiifed node's data if you have a data store which supports that operation. taptap can directly support that use case with an explicit "node identity" event: this node which didn't have a MAC/barcode now has one, go rewrite history. You'd get it once per node as it happens instead of having to scrutinize every hardware inventory to detect this condition.

Circling back to identification and addressing challenges, this is a classic database problem. The basic challenge is that we're trying to use gateway and node IDs as natural keys, but these attributes turn out to be mutable, and mutable natural keys cause no end of hardship. gateway_id=1, node_id=3 identifies a node at a point in time, which means it does not uniquely identify a node. The difficulty here is that we're trying to do it anyway.

The database solution is to use surrogate keys instead. So: what if taptap observe assigned a UUID for gateways/nodes and used that UUID to refer to that device from that point forward? taptap can move around these IDs as gateways renumber themselves, providing a greater degree of stability than the protocol itself. This approach encapsulates addressing details well enough that it would work for both past ("star") and potential future protocols without requiring consuming applications to change.

Some event sketches:

{
  "discovery": {
    "gateways": [
      {
        "id": "b6412389-5c9d-49c9-be6c-c920acc09f99",
        "mac": null,
        "version": null,
        "nodes": [
          {
            "id": "a44497d3-4d40-4eb0-8682-596a03e4eccc",
            "mac": null,
            "barcode": null,
            "version": null
          }
        ]
      }
    ]
  }
}
{
  "node_identity": {
    "id": "a44497d3-4d40-4eb0-8682-596a03e4eccc",
    "mac": "",
    "barcode": ""
  }
}
{
  "power_report": {
    "gateway": {
      "id": "b6412389-5c9d-49c9-be6c-c920acc09f99",
      "mac": null
    }
    "node": {
      "id": "a44497d3-4d40-4eb0-8682-596a03e4eccc",
      "mac": null,
      "barcode": null
    },
    "timestamp": "",
    "voltage_in": 44.25,
    "voltage_out": 40.8,
    "current": 5.8, 
    "dc_dc_duty_cycle": 0.9411764705882353,
    "temperature": 24.0,
    "rssi": 134
  }
}

In reply to:

Having the information about power and infrastructure in two separate event/messages is perfectly fine - the event structure is well defined, and information are split in the way any relational database would like them normalized. What you propose is to put everything in power report, even there is always some higher layer over the taptap which would do that correlation much better - especially when serial, address, versions tend to change very rarely, and there is no reason why to emits those for every power event. Such duplication is unnecessary - when any infrastructure information is received (much more rarely) then dedicated infrastructure event is fired. I do not need to parse every power report and see, that serial does or doesn't change (as it almost never does).

I propose denormalizing identifiers into power reports because these identifiers can and do change over time, meaning a normalized alternative would require very careful handling of the time component to be correct. There is not a higher layer which can do understand these how these identifiers change better than taptap observe: the best scenario is that a consuming application can do it exactly as well, and the more likely situation is that applications will take incorrect shortcuts. This is why I think taptap observe encapsulate that complexity instead. If taptap does not contain this complexity, we will end up with consuming applications which fail to handle edge cases in the current protocol and which fail to handle changes as the protocol evolves, for example by deciding that "almost never" is close enough to "never" not to handle it.

Would events like these address your use cases?

@willglynn
Copy link
Owner Author

Last comment. I started to backport your changes in this PR back to my fork so I can release it ASAP. It seems that you had need to rename persistent_file into state_file in your modifications of my original PR. But it is IMHO also wrong. This file has to do nothing with the state of the taptap process. State files on the Linux reflect state of the process. Not its persistent data. State files are NOT data files.

On the other hand file to store persistent data of the process could be called persistent-file, persistent-data or data-file, etc.

I named it "state file" because it is a file that contains state in the /var/lib meaning of "state":

5.8.1. Purpose

This hierarchy holds state information pertaining to an application or the system. State information is data that programs modify while they run, and that pertains to one specific host. Users must never need to modify files in /var/lib to configure a package's operation, and the specific file hierarchy used to store the data must not be exposed to regular users.

State information is generally used to preserve the condition of an application (or a group of inter-related applications) between invocations and between different instances of the same application. State information should generally remain valid after a reboot, should not be logging output, and should not be spooled data.

An application (or a group of inter-related applications) must use a subdirectory of /var/lib for its data. There is one required subdirectory, /var/lib/misc, which is intended for state files that don't need a subdirectory; the other subdirectories should only be present if the application in question is included in the distribution.

@litinoveweedle
Copy link

This in the event.rs do not produce required type = power-report in the JSON output

#[serde(rename = "snake_case", tag = "type")]
pub enum Event {
    PowerReport(PowerReportEvent),
}

@litinoveweedle
Copy link

Circling back to identification and addressing challenges, this is a classic database problem. The basic challenge is that we're trying to use gateway and node IDs as natural keys, but these attributes turn out to be mutable, and mutable natural keys cause no end of hardship. gateway_id=1, node_id=3 identifies a node at a point in time, which means it does not uniquely identify a node. The difficulty here is that we're trying to do it anyway.

The database solution is to use surrogate keys instead. So: what if taptap observe assigned a UUID for gateways/nodes and used that UUID to refer to that device from that point forward? taptap can move around these IDs as gateways renumber themselves, providing a greater degree of stability than the protocol itself. This approach encapsulates addressing details well enough that it would work for both past ("star") and potential future protocols without requiring consuming applications to change.

Please do not do this. First you complicate stuff. Second, you need to generate UUID from something. If you have long_address/serial you do not need UUID. If you don't have it yet, you have nothing to generate (not random but consistent) UUID from.

To the proposed structure of the events, it is again just complicate everything. It much more better to always print up-to-date complete structure of the persistent data instead providing partial updates. it doesn't matter what was the trigger for persistent data update. If you say that is is always 'easier to delete' something, than to not have it, it shall be better to print complete topology data.

I have feeling that more we discuss this issue least usable solution it became. It is so much easier already just to maintain my fork of the taptap and forget about the whole PR back thing. I really feel bad were this all. You was before not even fixing bugs. Then you gutted my work from PR, effectively removed me from contributors, changed everything to your liking, broke compatibility with something people really use and now you proposing changes to make it harder to work again. I do not understand, why do you keep asking me to comment things, if you always do it your way.

@litinoveweedle
Copy link

This in the event.rs do not produce required type = power-report in the JSON output

#[serde(rename = "snake_case", tag = "type")]
pub enum Event {
    PowerReport(PowerReportEvent),
}

What AI thinks:

Why it wasn’t working
The serde tag on the enum only affects serialization when you serialize the enum itself. Previously, the code was serializing PowerReportEvent directly, which doesn’t include a "type". By wrapping it in Event::PowerReport, the tagged enum adds "type": "power-report" as intended. Why it wasn’t working

@litinoveweedle
Copy link

This in the event.rs do not produce required type = power-report in the JSON output

#[serde(rename = "snake_case", tag = "type")]
pub enum Event {
    PowerReport(PowerReportEvent),
}

What AI thinks:

Why it wasn’t working The serde tag on the enum only affects serialization when you serialize the enum itself. Previously, the code was serializing PowerReportEvent directly, which doesn’t include a "type". By wrapping it in Event::PowerReport, the tagged enum adds "type": "power-report" as intended. Why it wasn’t working

Actually to be compatible with the previous format it needs to be:

#[serde(tag = "event_type", rename_all = "snake_case")]

@litinoveweedle
Copy link

litinoveweedle commented Nov 9, 2025

Your proposed changes in this PR generates error if state-file arg is used but not yet exists and it is created on the first infrastructure event:

EDIT: the following error is actually raised always, despite state-file is being successfully updated.

[2025-11-09T18:52:43Z ERROR taptap::observer] failed to persist state: error renaming state file: No such file or directory (os error 2)

EDIT is seems I was able to trace error to the case when relative path is being used for state-file, like:

--state-file ./taptap.json

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