Help needed with telegraf, modbus and starlark plugin

Hello to all of you,

i post this because i am stuck at a point where hours of research didnt help to get any further.
I pull data with telegraf modbus input from my smart energy meter all data that goes straight out to an influxdb is usable and all is fine with that.

But there are two sets of 4 int16 values, that needs to be calculatet like that:

Active energy+ [Wh] = ({register 512} · 2^48 + {register 513} · 2^32 + {register 514} · 2^16 + {register
515}) · 0.1 [Wh]

After some research i think [processor.strarlark] is the one that can do the job. So i followed some examples and tried some time for my own, but all i get is an error starting telegraf:

2021-05-14T12:50:37Z I! Loaded inputs: modbus
2021-05-14T12:50:37Z I! Loaded aggregators:
2021-05-14T12:50:37Z I! Loaded processors: starlark
2021-05-14T12:50:37Z I! Loaded outputs: influxdb
2021-05-14T12:50:37Z I! Tags enabled: host=MultiP
2021-05-14T12:50:37Z I! [agent] Config: Interval:5m0s, Quiet:false, Hostname:“MultiP”, Flush Interval:5m0s
2021-05-14T12:50:37Z E! [telegraf] Error running agent: could not initialize processor starlark: processor.starlark:11:2: got indent, want primary expression

I absolutly have ne clue what the Problem is here. If something is missing or are there language errors,
Or is this totaly the wrong way to handle the needed calculation ? I just want to get only the two calculatet values into the DB not the 8 raw values.

This is my conf:

[[inputs.modbus]]

TCP

controller=“tcp://192.168.2.19:502”
name = “KSEM”
slave_id = 1
timeout = 5
interval = “5m”
flush_interval = “5m”
holding_registers = [
{ name = “Active energy_pos1”, byte_order =“AB”, data_type = “UINT16”, scale=1.0, address = [512]},
{ name = “Active energy_pos2”, byte_order =“AB”, data_type = “UINT16”, scale=1.0, address = [513]},
{ name = “Active energy_pos3”, byte_order =“AB”, data_type = “UINT16”, scale=1.0, address = [514]},
{ name = “Active energy_pos4”, byte_order =“AB”, data_type = “UINT16”, scale=1.0, address = [515]},
{ name = “Active energy_neg1”, byte_order =“AB”, data_type = “UINT16”, scale=1.0, address = [516]},
{ name = “Active energy_neg2”, byte_order =“AB”, data_type = “UINT16”, scale=1.0, address = [517]},
{ name = “Active energy_neg3”, byte_order =“AB”, data_type = “UINT16”, scale=1.0, address = [518]},
{ name = “Active energy_neg4”, byte_order =“AB”, data_type = “UINT16”, scale=1.0, address = [519]},
]

[[processors.starlark]]
source = ‘’’
def apply(metric):
#Register 512-515 into var
pos1 = int(metric.fields[‘Active energy_pos1’])
pos2 = int(metric.fields[‘Active energy_pos2’])
pos3 = int(metric.fields[‘Active energy_pos3’])
pos4 = int(metric.fields[‘Active energy_pos4’])

calc new field

metric.fields[‘Netz_Bezug’] = ((pos1 * 281474976710656) + (pos2 * 4.294.967.296) + (pos3 * 65536) + pos4) / 10000

#Register 516-519 into var
neg1 = int(metric.fields[‘Active energy_neg1’])
neg2 = int(metric.fields[‘Active energy_neg2’])
neg3 = int(metric.fields[‘Active energy_neg3’])
neg4 = int(metric.fields[‘Active energy_neg4’])

calc new field

metric.fields[‘Netz_Einspeisung’] = ((neg1 * 281474976710656) + (neg2 * 4.294.967.296) + (neg3 * 65536) + neg4) / 10000

return metric

‘’’

I would be grateful if someone could take a look into it.

Kind regards
Dennis

Hi Dennis,

The error you are seeing is complaining about the lack of indentation in your Starlark script.

I added indention after the apply, made sure comment lines had a #, fixed your source quote marks and changed your field identifiers to “”. I think the below will get you past that error around indent:

source = '''
def apply(metric):
    #Register 512-515 into var
    pos1 = int(metric.fields["Active energy_pos1"])
    pos2 = int(metric.fields["Active energy_pos2"])
    pos3 = int(metric.fields["Active energy_pos3"])
    pos4 = int(metric.fields["Active energy_pos4"])

    #calc new field
    metric.fields["Netz_Bezug"] = ((pos1 * 281474976710656) + (pos2 * 4294967296) + (pos3 * 65536) + pos4) / 10000

    #Register 516-519 into var
    neg1 = int(metric.fields["Active energy_neg1"])
    neg2 = int(metric.fields["Active energy_neg2"])
    neg3 = int(metric.fields["Active energy_neg3"])
    neg4 = int(metric.fields["Active energy_neg4"])

    #calc new field
    metric.fields["Netz_Einspeisung"] = ((neg1 * 281474976710656) + (neg2 * 4294967296) + (neg3 * 65536) + neg4) / 10000

    return metric

'''

Also if you add debug = true into the agent part of your config it can also help with further debugging.

Let me know if that helps, thanks!

Hi helenosheaa,

thank you for your reply. I am not deep into coding so i wasn’t afraid of the importance of indention.
Your version indeed get a step futher. The actual error now is:

2021-05-14T17:45:17Z E! [telegraf] Error running agent: could not initialize processor starlark: processor.starlark:9:80: got float literal, want ‘)’

I understand that a division results in a float value. But the error remains the same, even if i cut the division (/10000). So i dont see what the error is about in this script.
Do you have clue ?

Thanks for spending your time and have a nice day!
Dennis

Hi Dennis,

The error message is regarding the multiple . delimiters in 4.294.967.296 if you change it to 4294967296 it should work. Same applies on the calculation for the field “Netz_Einspeisung”.

Hope that helps.

Thanks,
Helen

Hi Helen,

after you pointed it out it was so obvious to me that i am ashamed of not realizing it on my own…
Now it works the way i hoped for ;D

Thank you very much and have a nice weekend !!
Dennis

Hi Dennis,

No problem you are very welcome!

Helen

Hi,
I am able to use Starlark with Modbus plugin. But, i am not able to work with OPC UA plugin. Does Starlark work with OPC UA Plugin at all?

thanks
Vikas

@vkhemani
This has nothing to do with each other. Starlark is a Processor plugin, i.e. it basically works with all input plugins.