I had with @DanielH a good discussion
# general
j
I had with @DanielH a good discussion today on making the bloblang part more easy. We were thinking of something like this (I modified what we had in our meeting after discussing with @Mateusz ):
Copy code
yaml
tagProcessor:
  defaultProtocolSettings: opcua

  customProtocolSettings: # alternative to specify more details to defaultProtocolSettings
  - tagFolder: meta("opcua_tag_group")
  - tagName: meta("opcua_tag_name")
  - tagType: meta("opcua_tag_type")

  enterprise: "enterprise-of-kings"

  groupConditions:
  - if: always()
    groupTo: 
      - site: "jeremy-vm"
  - if: meta("modbus_slave_id") == 10
    groupTo:
      - area: "daughterCompanyA"
        line: "line_ABC"
  - if: meta("modbus_address") == "B123"
    groupTo:
      - tagName: "temperature"
What are your thoughts on this all?
Alternative: - enterprise is set automatically - added a replaceAll to remove special characters, etc.
Copy code
yaml
tagProcessor:
  defaultProtocolSettings: opcua

  conditions:
  - if: always()
    groupTo: 
      - site: "jeremy-vm"
    setTagOverride:
        - tagFolder: meta("opcua_tag_group") # optional
        - tagName: meta("opcua_tag_name") # optional 
        - tagType: meta("opcua_tag_type") #optional 
        - tagMetadata: # optional 
            - serial_number: "123"
  - if: meta("modbus_slave_id") == 10
    groupTo:
      - area: "daughterCompanyA"
        line: "line_ABC"
  - if: meta("modbus_address") == "B123"
    groupTo:
      - tagName: "temperature"

  replaceAll:
   - tagFolder:
       - "/[^a-zA-Z0-9_]/g": "" # remove all special characters from tagFolder
d
something like this:
Copy code
yaml
tagProcessor:
    protocol: opcua

    setTagOverride:
        - tagFolder: "opcua_tag_group" # optional
        - tagName: "opcua_tag_name" # optional 
        - tagType: "opcua_tag_type" #optional 
        - tagMetadata: # optional 
            - serial_number: "123"
    renaming:
        - {
        "thisIs_a_very_4234VB_long.OPCUA.stupidVendor_notMakeAnySenseName": "tempInCabinet"
        "thisIs_another_very_4fa99434aB_long.OPCUA.stupidVendor_notMakeAnySenseName": "pressureInCabinet"
        }

    grouping:
        group:
           - from: * # group all
           - name: *
           - to: "site" # allowed is "site", "area", "line" "machine", To name if not used
           - name: "jeremy-vm"
        group: 
            - from: "modbus_slave_id"
            - ifMatched: 10 # optional, if not used all matches from - from: will be used
            - to: "area.line"
            - name: "daughterCompanyA.line_ABC"
        group: 
            - from: "modbus_address" 
            - ifMatched: "B123"
            - name: "temperature"
            
        group: 
            - from: "modbus_address" 
            - ifMatched: "A56"
            - name: "temperature"
            - jsonOutput: true # combines all values to a json struct 

  replaceAll:
   - tagFolder:
       - "/[^a-zA-Z0-9_]/g": "" # remove all special characters from tagFolder
j
We have now the attached file as proposal with the following reasons: - we need to include the meta() so that the user can match on metadata as well as the value itself with this.content(). It might not be that intuitive for OT people, but required to not cause confusion for IT people. I think overall we made an improvement for OT people. - we have basic grouping, basic renaming etc. all at the beginning - only then follows the advanced mode with conditions What are your thoughts @Brian Pribe @Diederik ? would you prefer this over the current bloblang implementation? would you give this to one of your customers for self-service? Also @Mateusz to give his input as well 🙂
d
For me currently it's difficult to see the value/why this should be changed. And certainly why this should be made more complex (my impression on first sight) I'm no bloblang expert (as seen by the issues i had last week) Maybe we should have a teams meeting with multiple people what/why/how/... I cannot give useful thoughts before understanding this all better. But obviously i'm interested to learn more! 😄
b
I’m in the same boat as Diederik. I’m working towards using bloblang, but I’m still at the POC stage of getting data in and doing rudimentary visuals. My biggest concerns are with installation and management of UMH and other services on-prem and at the edge. NodeRED is doing just enough for me to get by, but obviously scale will be an issue and this is where bloblang will come in.
d
i can confirm this is the way :p @Brian Pribe maybe you should take a look at my current issue before you go too far hahaha
i have around 5 of these :p
this is (getting) unmanagable
so indeed, nodered has to go hahaha
d
Have you tried using a script instead? that could shorten everything. Or create subnodes.
Could you instead use "meta" as default and add an optional option for all settings like - disableMeta: true or something like that, in case the user does not want to use meta
b
Holy F*ck
d
everything has to be understandable by my costumer
it's co engineering ;p so it can not be too difficult
j
i know you really don't like it, but currently I see no way around it without causing more confusion :/
that is good feedback! I also think it is more complex, but heard now from multiple people that this is more easy to understand and the other thing is more complex.
that is also good to hear! what are the biggest concerns around installation and management?
you are not alone with this 😄 one of our customers has also such big Node-RED flows. and yes, it is nice to get started. but at some point one needs to switch the programmign style away from visuals to code in order to understand larger applications
b
Our concerns with installation and management is being able to do this at scale. Whether customers want to manage it themselves or we are managing their’s.
j
Let me add two more ideas: 1. batch messages of the last second into a single JSON payload (I think wish from @krgrsebastian , @Diederik, @DanielH ) 2. in the management console, don't show the full YAML. Instead show multiple text boxes e.g., a text box for conditions.
Also uploaded it to learn, so the latest proposal can always be seen in a nice to digest format https://learn.umh.app/course/request-for-comment-new-protocol-converter-configuration/
New thought: adding an external MQTT broker should be made more easily than the example here "importing external mqtt broker"https://learn.umh.app/course/mastering-data-transformation-with-benthos-and-bloblang-in-19-examples-2/
b
Took me a minute to fully understand what it's doing, but this gives you a way to normalize the topic structure of another broker into a UMH structured broker. If I understand correctly in this example, you can take all of the topics, configure the topic variables and their values that it will be comparing to transform, compare those topics with the variables to see if there's a match, and redistribute the topics into the new broker with added rules to validate the payload.
j
Exactly! But the code looks a little bit scary. But I think it would be possible easily to transfer the logic to the configuration I pasted, let me try out later
This is how it would look like. Still looks a little bit scary, don't you think as well? any ideas?
Copy code
yaml
tagProcessor:
  defaultProtocolSettings: none  # Basic Setting, None which requires customProtocolSettings to be set

  customProtocolSettings:         # Protocol Overrides
    tagFolder: meta("mqtt_topic").replace_all("<topic>", "").replace_all("/", ".") # Remove the <topic> prefix from all topics, then convert all '/' characters to '.'
    
    tagName: meta("mqtt_topic").split('/').slice(-1) # take the most right part of the topic as the tagName
    
    tagType: string # convert everything to a json
    
  groupTo:                        # Basic Grouping
    enterprise: "MyEnterprise"
    site: "MainSite"

  renaming:                       # Tag Renaming
    "weirdTagID3334": "temperature"
  
  conditions:                     # Advanced Conditions
    - if: always()
      tagOverrides:
        tagMetadata:
          mqtt_broker: "192.168.1.1"

  replaceAll:                     # Regex Replacements
    tagFolder:
      "/[^a-zA-Z0-9_\\/]/g": ""   # Sanitize tag folders
    tagName:
      "/[^a-zA-Z0-9_]/g": ""      # Sanitize tag names

  advancedProcessing:             # Advanced Processing (Disabled)
    enabled: false
    script: |
      root = this
      # Custom Bloblang script
d
Copy code
yaml
customProtocolSettings:         # Protocol Overrides
    tagFolder: "mqtt_topic"
       useMeta: true # default is true i omitted
       stringManipulation: "replace"
          type: "all" 
              - "/"
               - "."
    tagName: meta("mqtt_topic").split('/').slice(-1) # take the most right part of the topic as the tagName
    tagName: "mqtt_topic"
       useMeta: true # default is true i omitted
       stringManipulation: "slice"
              - "-1"
    tagType: string # convert everything to a json
How about something like this? i don't know if it makes any more sense or not?
j
Still no fan of the meta flag :). it I love the idea with the string manipulation, let me look at it tomorrow!
d
I think that if the processor is supposed to make everything easier and more intuitive the meta should not be used. If you have a optional useMeta: false which is default true then you could skip meta in case you are doing something special.. for ease of use just skip all programming mumbo jumbo and keep a clean an easy config.. in my opinion this is the easiest way for a "normal" user to understand it.. for anyone that is more advanced the bloblang should not be a problem either.. In my case i am always thinking about the next person that should maintain the system and what potential skills they have, and from my experience both from my current workplace and others the IT-level(programing) in the industry is quite low..
t
I’m in favor of configuration files, especially for templates and a standardized ui, because many of the end users will get frustrated with bloblang as the only way. My experience with bloblang isn’t great at the moment but ChatGPT, google, umh blog, and practice helped understand how it works, but I was getting frustrated, and I have more patience for these things than most. The configuration files can help to minimize the need to understand bloblang syntax and minimize errors on the output, with a common output ready for umh Uns to consume. This reminds me of telegraf, but I’m not a fan of toml. So I was thankful to find starlark. It’s much more in line with yaml, so if you’re used to homeassistant, or docker compose this feels familiar.
If umh needs to change the output , then this also minimizes the need for the user to refactor code.
This is the value of putting repetitive code in custom nodes that are more clear on the purpose . I’ve run into this with ladder vs structured text in plc code. Users tend to understand ladder more, so putting st in a function block simplified it for them.
13 Views