sunspec / models

SunSpec Model Definitions
Apache License 2.0
94 stars 57 forks source link

Block type indication and ordering rules (fixed or repeating) not in JSON schema #209

Closed wz2b closed 1 year ago

wz2b commented 3 years ago

This might be a misunderstanding on my part but I need some clarity on something. In the XML schema, every block had a type which defaulted to fixed.

When you look at a model like 132 (volt-watt curve) it is very obvious how it works:

The JSON equivalent of that isn't like that. Its structure is:

   group: {
      groups: [
         /* one group, which describes what a curve looks like */
      ],
      points: {
           /* description of the fixed block
      }
    ]
  }

I find this far, far more confusing and am wondering if somebody can set the record straight on how to generate code implementations based on this structure. The implication as I understand it is that the group.points is the start of the model (in register space), and that the group.groups[] follow that. I don't know if "L" includes the length of the entire thing (fixed + repeating), or do I have to look into the repeating block(s) to determine and follow their lengths. I think it's implied that the group named 'curve' is meant to be a repeating block, and as such, it must appear at the end.

To me, many of these rules aren't obvious, and the json schema doesn't tighten them down. You need outside semantics to understand what is going on. With the XML it was more obvious to me... the only "outside informatino" I felt I needed was the knowledge that repeating blocks must follow the fixed block.

Can somebody help me tighten up my understanding of this? Then, following that, I want to start a discussion on what we do about supporting code generation. For simple models it is easy, for these tables less so.

I know there is a lot to unpack here. Sorry.

bobfox commented 3 years ago

Here are the semantics of the definition content:

A group can contain a set of 0 or more points and a set of 0 or more groups. Points come before groups in any context where there is a concept of order such as Modbus.

Models have a single top-level group that represents the model content.

All models start with an ID point and L point in the top-level group. The L point contains the remaining length of the model in any context where length has meaning such as Modbus.

The group ‘count’ attribute indicates if the group repeats. The following cases apply for repeating group count:

If the value of count is 0, it is a legacy model where the number of repeating instances of the group are calculated by using this formula: ( L – points length)/group length. In the legacy case, the group can only contain points and no groups.

If the value of count is a number > 0, there are always that many instances of the group in a model instance.

If the value of count is a point name in the top-level model group, the number of group instances in the model instance is contained in the point for that model instance.

I don’t think any of these usage semantics can be represented in the JSON schema. All these statements are in the SunSpec Device Information Model Specification but perhaps they should be restated together in this way to make it clearer. Does this clarify it for you, or are there still pieces missing? Is there a way to express this better to make it more clear?

bobfox commented 3 years ago

I meant to emphasize that the contents of the L point is the remaining length after the L point.

wz2b commented 3 years ago

I meant to emphasize that the contents of the L point is the remaining length after the L point.

Just to be certain, this means the length of ALL of the components of this model including the fixed block, and n * repeated blocks (or groups or whatever you call them), correct? Put in alternative terms: you can look at the current address, plus L and you'll find the Model ID of the next model down? I'm pretty sure that's the case because experimentally I was able to walk all the models on an SMA SB-3.0 US and get results that generally make sense:

Found model 1 len 66 -- common model
Found model 11 len 13 at 40070 – information about the ethernet interface
Found model 12 len 98 at 40085 – information about the IP networking layer
Found model 102 len 50 at 40185 – split-phase inverter monitoring, integer data
Found model 120 len 26 at 40237 – nameplate ratings
Found model 121 len 30 at 40265 – basic settings
Found model 122 len 44 at 40297 – extended measurements and status
Found model 123 len 24 at 40343 – immediate inverter controls
Found model 124 len 24 at 40369 – basic storage controls
Found model 126 len 64 at 40395 – static volt-var arrays
Found model 127 len 10 at 40461 – parameterized frequency/watt parameters
Found model 128 len 14 at 40473 – dynamic reactive current curve
Found model 131 len 64 at 40489 – watt-powerfactor curve
Found model 132 len 64 at 40555 – volt-watt curve
Found model 160 len 128 at 40621 – mppt
No more models

I don’t think any of these usage semantics can be represented in the JSON schema.

I agree. I don't think there is, either. I can't really think of a great way to improve this. You could put back an attribute fixed or repeated that might make it more obvious the intent there, because the understanding that repeated blocks come after fixed blocks is prior knowledge you already have to possess.

If the value of count is 0, it is a legacy model where the number of repeating instances of the group are calculated by using this formula: ( L – points length)/group length. In the legacy case, the group can only contain points and no groups.

Let me pick on model 132 again as my example:

{
    "group": {
        "desc": "Volt-Watt ",
        "groups": [
            {
                "count": 0,
                "name": "curve",
                "points": [
                    { ... }
                ]
           }
       ]
   }
}

Count is 0. The 'groups' has one 'group' which contains only points. So in addition to what you said, is it true that the outer list of groups must contain exactly one entry (one group) an an additional rule?

In this specific example, the fixed block contains two parameters - Ncrv and Npt - that also give you some information here, so the way I interpret this is that ( L – points length )/group length is giving me an overall length, but to figure out the geometry (i.e. it's 1 table of 20 points, or it's 4 tables of 5 points each) I really need to look at Ncrv and Npt ? The trouble with that is just that you have to have knowledge in order to be able to generically parse. (In my case I'm parsing to generate code, but I think the same rules apply even if you're trying to parse to a Map<String,Object>)

Does it seem like I have all of this right?

bobfox commented 3 years ago

You are expressing the usage of the contents of the L point correctly. For SunSpec Modbus, the ability to locate each of the models in the way you describe is the foundation for finding specific content in SunSpec Modbus maps that vary across implementations due to different models being present with different ordering.

The only time the contents of points should be used for model length determination is when they are specified in the model definition as containing the group count. In the case where the group count is set to 0 in the definition, only the formula should be used to determine model length: ( L – points length )/group length. The “legacy” models that use the count = 0 mechanism have always been required to allocate all the space in the Modbus register map based on that formula. This was one of the issues with the previous modeling. In model 132, for example, for each curve instance supported needs to allocate the Modbus registers for 20 points, even only if 2 point are used. The NCrv and NPt points in those cases are indications of what curves and points are being used out of the ones present in the Modbus map. The NCrv and NPt points in those cases may not necessarily relate to the actual model instance length.