Skip to content

Instantly share code, notes, and snippets.

@sjoerdvanderhoorn
Created December 29, 2018 14:04
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sjoerdvanderhoorn/202842debe40b8e662d4022cb36255b7 to your computer and use it in GitHub Desktop.
Save sjoerdvanderhoorn/202842debe40b8e662d4022cb36255b7 to your computer and use it in GitHub Desktop.
Omnik-solar

Omnik-solar provides a custom node that can listen to incoming messages from an Omnik converter. The flow opens TCP port 8899. Your Omnik converter needs to be configured to send statistics to this address.

Inverter configuration

  • Log on to Omnik inverter
  • Open menu Advanced | Remote Server
  • On the Server B row:
  • Set IP address to the (local) IP address of your server.
  • Set Domain name to the domain name of your server (or leave blank).
  • Set Port to 8899.
  • Set Connection to TCP.
  • Click Save
  • Open port 8899 in your firewall

Output

Data from the Omnik inverter is parsed and available as below properties of the msg-object.

Note, the inverter only connects and outputs data when enough sunlight is received for the internals to be awake. No data is returned at night.

Production

  • msg.omnik.currentProduction - Current production in W
  • msg.omnik.productionToday - Today's production in kWh
  • msg.omnik.productionTotal - Total production in kWh

Operational

  • msg.omnik.temperature - Current temperature in C
  • msg.omnik.hoursActive - Total hours running

Power

  • msg.omnik.pvVoltageDc1
  • msg.omnik.pvVoltageDc2
  • msg.omnik.pvVoltageDc3
  • msg.omnik.ivAmpsDc1
  • msg.omnik.ivAmpsDc2
  • msg.omnik.ivAmpsDc3
  • msg.omnik.pvVoltageAc1
  • msg.omnik.pvVoltageAc2
  • msg.omnik.pvVoltageAc3
  • msg.omnik.ivAmpsAc1
  • msg.omnik.ivAmpsAc2
  • msg.omnik.ivAmpsAc3
  • msg.omnik.frequencyAc

Inverter

  • msg.omnik.wifiSerialNumber
  • msg.omnik.inverterMainFirmwareVersion
  • msg.omnik.inverterSlaveFirmwareVersion
  • msg.omnik.inverterStatus

Debug

  • msg.omnik.rawBuffer
  • msg.omnik.rawString
[
{
"id": "2a4285cd.7cbdea",
"type": "subflow",
"name": "live",
"info": "Opens local port 8899 for Omnik inverter to connect to and send statistics.\n\n# Inverter configuration\n* Log on to Omnik inverter\n* Open menu **Advanced | Remote Server**\n* On the **Server B** row:\n * Set **IP address** to the IP address of your server.\n * Set **Domain name** to the domain name of your server (or leave blank).\n * Set **Port** to **8899**.\n * Set **Connection** to **TCP**.\n * Click **Save**\n\n# Output\nData from the Omnik inverter is parsed and available as below properties of the msg-object.\n\nNote, the inverter only connects and outputs data when enough sunlight is received for the internals to be awake. No data is returned at night.\n\n## Production\n* `msg.omnik.currentProduction` - Current production in W\n* `msg.omnik.productionToday` - Today's production in kWh\n* `msg.omnik.productionTotal` - Total production in kWh\n\n## Operational\n* `msg.omnik.temperature` - Current temperature in C\n* `msg.omnik.hoursActive` - Total hours running\n\n## Power\n* `msg.omnik.pvVoltageDc1`\n* `msg.omnik.pvVoltageDc2`\n* `msg.omnik.pvVoltageDc3`\n* `msg.omnik.ivAmpsDc1`\n* `msg.omnik.ivAmpsDc2`\n* `msg.omnik.ivAmpsDc3`\n* `msg.omnik.pvVoltageAc1`\n* `msg.omnik.pvVoltageAc2`\n* `msg.omnik.pvVoltageAc3`\n* `msg.omnik.ivAmpsAc1`\n* `msg.omnik.ivAmpsAc2`\n* `msg.omnik.ivAmpsAc3`\n* `msg.omnik.frequencyAc`\n\n## Inverter\n* `msg.omnik.wifiSerialNumber`\n* `msg.omnik.inverterMainFirmwareVersion`\n* `msg.omnik.inverterSlaveFirmwareVersion`\n* `msg.omnik.inverterStatus`\n\n## Debug\n* `msg.omnik.rawBuffer`\n* `msg.omnik.rawString`",
"category": "omnik",
"in": [],
"out": [
{
"x": 400,
"y": 60,
"wires": [
{
"id": "d625a814.e8f098",
"port": 0
}
]
}
]
},
{
"id": "ff1b0584.ad0a48",
"type": "tcp in",
"z": "2a4285cd.7cbdea",
"name": "",
"server": "server",
"host": "",
"port": "8899",
"datamode": "single",
"datatype": "buffer",
"newline": "\\x16",
"topic": "",
"base64": false,
"x": 80,
"y": 60,
"wires": [
[
"d625a814.e8f098"
]
]
},
{
"id": "d625a814.e8f098",
"type": "function",
"z": "2a4285cd.7cbdea",
"name": "Parse Omnik data",
"func": "var omnik = msg.payload;\n\nmsg.omnik = {};\n\n// Production\nmsg.omnik.currentProduction = omnik.readInt16BE(59); // W\nmsg.omnik.productionToday = omnik.readInt16BE(69) / 100; // kWh\nmsg.omnik.productionTotal = omnik.readInt32BE(71) / 10; // kWh\n// Current operation\nmsg.omnik.temperature = omnik.readInt16BE(31) / 10; // C\nmsg.omnik.hoursActive = omnik.readInt32BE(75);\n// Power\nmsg.omnik.pvVoltageDc1 = omnik.readInt16BE(33) / 10;\nmsg.omnik.pvVoltageDc2 = omnik.readInt16BE(35) / 10;\nmsg.omnik.pvVoltageDc3 = omnik.readInt16BE(37) / 10;\nmsg.omnik.ivAmpsDc1 = omnik.readInt16BE(39) / 10;\nmsg.omnik.ivAmpsDc2 = omnik.readInt16BE(41) / 10;\nmsg.omnik.ivAmpsDc3 = omnik.readInt16BE(43) / 10;\nmsg.omnik.pvVoltageAc1 = omnik.readInt16BE(51) / 10;\nmsg.omnik.pvVoltageAc2 = omnik.readInt16BE(53) / 10;\nmsg.omnik.pvVoltageAc3 = omnik.readInt16BE(55) / 10;\nmsg.omnik.ivAmpsAc1 = omnik.readInt16BE(45) / 10;\nmsg.omnik.ivAmpsAc2 = omnik.readInt16BE(47) / 10;\nmsg.omnik.ivAmpsAc3 = omnik.readInt16BE(49) / 10;\nmsg.omnik.frequencyAc = omnik.readInt16BE(57) / 100;\n// Inverter\nmsg.omnik.wifiSerialNumber = omnik.readInt32LE(4);\nmsg.omnik.inverterSerialNumber = omnik.toString(\"utf8\", 15, 31);\nmsg.omnik.inverterMainFirmwareVersion = omnik.toString(\"utf8\", 101, 116);\nmsg.omnik.inverterSlaveFirmwareVersion = omnik.toString(\"utf8\", 117, 136);\nmsg.omnik.inverterStatus = omnik.toString(\"utf8\", 155, 170);\n// Debug\nmsg.omnik.rawBuffer = omnik;\nmsg.omnik.rawString = omnik.toString();\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 260,
"y": 60,
"wires": [
[]
]
},
{
"id": "4eb05ef.32d9ea",
"type": "subflow:2a4285cd.7cbdea",
"z": "14cd401d.1b1e3",
"name": "",
"x": 110,
"y": 1140,
"wires": [
[
"d48d9e1c.99c0d"
]
]
},
{
"id": "d48d9e1c.99c0d",
"type": "debug",
"z": "14cd401d.1b1e3",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "omnik",
"x": 250,
"y": 1140,
"wires": []
}
]
@iepmaatje
Copy link

Hi Sjoerd, Thank you for this flow, very helpful !
Do you think you could point me in how I could add this data to PVoutput ?
I don't believe it would be difficult, but the problem is that I have no clue what to do ...
Erwin

@sjoerdvanderhoorn
Copy link
Author

Thanks, although I am afraid I won't be able to help you much from here as I have not used PVoutput before. You can probably use the output of this flow and push it to their API.

See: https://pvoutput.org/help/api_specification.html#api-add-status

@kuba-orlik
Copy link

Thanks for that, works like a charm!

@teeffelen
Copy link

teeffelen commented May 24, 2021

Hey, is it possible that the custom remote server B and C have disappeared from the remote server screen?
I do see the default server A, inspecting this element in the browser shows it is now sending data to solarmanpv as the default address for server A (instead of the Omnikportal which used to be the default).

I wonder if Solarman disabled the remote server feature to block free alternatives like this one :/

@kuba-orlik
Copy link

I hope not! What is your inventer model? I still have the custom servers option, hopefully no OTA update will change that

@teeffelen
Copy link

teeffelen commented May 25, 2021

The inverter itself is the Omniksol-8k-TL2 (Omnik8000tl) with an Omnik TL2-3P Internal Data Collector, I just tried the soft and hard reset options on the data logger and the Server B and C are still gone (along with the save button):

servers

This is the case for both of my inverters, which are both running the following firmware:
H4.01.51MW.2.01W1.0.65(2018-02-271-D)

I still want to try to hack the B and C servers (and save button) back, could you be so kind to share the complete HTML of the form?
(Using a code-block on github would be better to copy/paste from :)

It should look something like this (but with extra servers and a save button):

image

Note that the display:none items in the form are just the IP and address of server A, I'd like to see the source-code of the other servers and the safe button (hoping they just removed the servers/button, not the back-end functionality).

@kuba-orlik
Copy link

kuba-orlik commented May 26, 2021

I'm far away from the inverter right now and cannot access the local network. Will send you the details when I'm there!

BTW, did you upgrade manually or did the update happen automatically? I'm scared it's gonna get me as well...

@kuba-orlik
Copy link

@teeffelen it took some time, but here's the DOM of the form:

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <link href="css/slave.css" rel="Stylesheet" type="text/css" />
    <script type="text/javascript" src="js/slave.js"></script>
    <script type="text/javascript" src="js/utils.js"></script>
    <script type="text/javascript" src="js/remote.js"></script>
  </head>
  <body class="in_body" onload="init_server_setting_form(3)">
    <div
      class="div_c"
      style="margin-left: 40px; margin-right: 30px; font-family: Arial"
      id="main_div"
    >
      <div style="height: 400px">
        <font class="blue s16 b" id="tit1">Remote server setting</font>
        <div class="sp_10"></div>
        <div style="overflow: auto">
          <iframe
            style="
              border-style: none;
              width: 100%;
              height: 0px;
              border-spacing: 0px;
            "
            id="remote_test_iframe"
            allowtransparency="true"
            frameborder="0"
          ></iframe>
          <form
            name="form_server_setting"
            method="post"
            action="do_server.html"
          >
            <div class="tab_1 w_58" id="tx1">Server</div>
            <div class="tab_1 w_103" id="tx2">IP address</div>
            <div class="tab_1 w_153" id="tx3">Domain name</div>
            <div class="tab_1 w_45" id="tx4">Port</div>
            <div class="tab_1 w_70" id="tx5">Connection</div>
            <div class="tab_1 w_42" id="tx6">Status</div>
            <div class="tab_1 w_32" id="tx7">Test</div>
            <div class="cl"></div>
            <div class="sp_5"></div>
            <div class="tab_2 w_58" id="tx8">Server A</div>
            <div class="tab_2">
              <input
                type="text"
                class="w_103 bor_0"
                readonly="readonly"
                style="background-color: #e1e1e1"
                id="ip_d"
              />
            </div>
            <div class="tab_2">
              <input
                type="text"
                class="w_153 bor_0"
                readonly="readonly"
                style="background-color: #e1e1e1"
                id="ds_d"
              />
            </div>
            <div class="tab_2">
              <input
                type="text"
                class="w_45 bor_0"
                readonly="readonly"
                style="background-color: #e1e1e1"
                id="pt_d"
              />
            </div>
            <div class="tab_2">
              <input
                type="text"
                class="w_70 bor_0"
                readonly="readonly"
                style="background-color: #e1e1e1"
                id="cn_d"
              />
            </div>
            <div class="tab_2" style="display: none">
              <input
                type="text"
                class="w_103 bor_0"
                name="cnmo_ip_a"
                id="ip_1"
              />
            </div>
            <div class="tab_2" style="display: none">
              <input
                type="text"
                class="w_153 bor_0"
                name="cnmo_ds_a"
                id="ds_1"
              />
            </div>
            <div class="tab_2" style="display: none">
              <input
                type="text"
                class="w_45 bor_0"
                name="cnmo_pt_a"
                id="pt_1"
              />
            </div>
            <div class="tab_2" style="display: none">
              <select name="cnmo_tp_a" class="w_70 bor_0" id="tp_1">
                <option value="TCP">TCP</option>
                <option value="UDP">UDP</option>
              </select>
            </div>
            <div class="tab_2 w_42 tc" style="height: 20px">
              <img
                id="a_ok"
                src="image/p_ok.png"
                style="display: none; width: 22px; height: 22px"
                title="Pingable"
              /><img
                id="a_no"
                src="image/p_no.png"
                style="display: none; width: 22px; height: 22px"
                title="Unpingable"
              />
            </div>
            <div class="tab_2 w_32 tc">
              <input
                type="button"
                class="btn_t"
                onclick="remote_server_test('a','')"
                id="btn1"
                style="background-image: url('image/test.png')"
              />
            </div>
            <div class="cl"></div>
            <div class="line3"></div>
            <div class="tab_2 w_58" id="tx9">Server B</div>
            <div class="tab_2">
              <input
                type="text"
                class="w_103 bor_0"
                name="cnmo_ip_b"
                id="ip_2"
                onfocus="txtOnfocus(this)"
                onblur="txtOnblur(this)"
              />
            </div>
            <div class="tab_2">
              <input
                type="text"
                class="w_153 bor_0"
                name="cnmo_ds_b"
                id="ds_2"
                onfocus="txtOnfocus(this)"
                onblur="txtOnblur(this)"
              />
            </div>
            <div class="tab_2">
              <input
                type="text"
                class="w_45 bor_0"
                name="cnmo_pt_b"
                id="pt_2"
                onfocus="txtOnfocus(this)"
                onblur="txtOnblur(this)"
              />
            </div>
            <div class="tab_2">
              <select name="cnmo_tp_b" class="w_70 bor_0" id="tp_2">
                <option value="TCP">TCP</option>
                <option value="UDP">UDP</option>
              </select>
            </div>
            <div class="tab_2 w_42 tc" style="height: 20px">
              <img
                id="b_ok"
                src="image/p_ok.png"
                style="display: none; width: 22px; height: 22px"
                title="Pingable"
              /><img
                id="b_no"
                src="image/p_no.png"
                style="display: none; width: 22px; height: 22px"
                title="Unpingable"
              />
            </div>
            <div class="tab_2 w_32 tc">
              <input
                type="button"
                class="btn_t"
                onclick="remote_server_test('b','')"
                id="btn2"
                style="background-image: url('image/test.png')"
              />
            </div>
            <div class="cl"></div>
            <div class="line3"></div>
            <div class="tab_2 w_58" id="tx10">Server C</div>
            <div class="tab_2">
              <input
                type="text"
                class="w_103 bor_0"
                name="cnmo_ip_c"
                id="ip_3"
                onfocus="txtOnfocus(this)"
                onblur="txtOnblur(this)"
              />
            </div>
            <div class="tab_2">
              <input
                type="text"
                class="w_153 bor_0"
                name="cnmo_ds_c"
                id="ds_3"
                onfocus="txtOnfocus(this)"
                onblur="txtOnblur(this)"
              />
            </div>
            <div class="tab_2">
              <input
                type="text"
                class="w_45 bor_0"
                name="cnmo_pt_c"
                id="pt_3"
                onfocus="txtOnfocus(this)"
                onblur="txtOnblur(this)"
              />
            </div>
            <div class="tab_2">
              <select name="cnmo_tp_c" class="w_70 bor_0" id="tp_3">
                <option value="TCP">TCP</option>
                <option value="UDP">UDP</option>
              </select>
            </div>
            <div class="tab_2 w_42 tc" style="height: 20px">
              <img
                id="c_ok"
                src="image/p_ok.png"
                style="display: none; width: 22px; height: 22px"
                title="Pingable"
              /><img
                id="c_no"
                src="image/p_no.png"
                style="display: none; width: 22px; height: 22px"
                title="Unpingable"
              />
            </div>
            <div class="tab_2 w_32 tc">
              <input
                type="button"
                class="btn_t"
                onclick="remote_server_test('c','')"
                id="btn3"
                style="background-image: url('image/test.png')"
              />
            </div>
            <div class="cl"></div>
            <div class="line3"></div>
            <div
              style="width: 520px; margin-top: 15px; margin-left: 4px"
              class="tr"
            >
              <input
                type="button"
                class="btn"
                id="btn4"
                onclick="server_setting_apply(3)"
                value="Save"
              />
            </div>
          </form>
        </div>
      </div>
    </div>
    <script type="text/javascript">
      initPageText();
      ready();
    </script>
  </body>
</html>

@teeffelen
Copy link

teeffelen commented Apr 23, 2022

So it has been a year, but I finally found time to try this again and this time actually got some data in NodeRED (By abusing the default servers domain name, since I still can't use server B/C).

Anyways, the default server seems to use some different return value as the data in NodeRED is kind of garbage:
image

Any ideas on how to convert the data properly?

Here is the rawBuffer:

[165,86,0,16,65,0,1,155,142,76,38,2,3,208,178,1,22,0,0,0,0,0,0,0,5,60,120,1,100,1,72,52,46,48,49,46,53,49,77,87,46,50,46,48,49,87,49,46,48,46,54,53,40,50,48,49,56,45,48,50,45,50,55,49,45,68,41,0,0,0,240,254,107,215,179,61,49,57,50,46,49,54,56,46,51,46,50,49,0,0,0,0,32,1,1,2,1,52,21,165,86,0,16,65,0,2,155,142,76,38,2,13,208,178,1,32,0,0,0,0,0,0,0,5,60,120,1,100,1,72,52,46,48,49,46,53,49,77,87,46,50,46,48,49,87,49,46,48,46,54,53,40,50,48,49,56,45,48,50,45,50,55,49,45,68,41,0,0,0,240,254,107,215,179,61,49,57,50,46,49,54,56,46,51,46,50,49,0,0,0,0,32,1,1,2,1,73,21,165,86,0,16,65,0,3,155,142,76,38,2,23,208,178,1,42,0,0,0,0,0,0,0,5,60,120,1,100,1,72,52,46,48,49,46,53,49,77,87,46,50,46,48,49,87,49,46,48,46,54,53,40,50,48,49,56,45,48,50,45,50,55,49,45,68,41,0,0,0,240,254,107,215,179,61,49,57,50,46,49,54,56,46,51,46,50,49,0,0,0,0,32,1,1,2,1,94,21]

@unix1234
Copy link

I have the same problem. Is there a solution out there?

@teeffelen
Copy link

teeffelen commented Mar 15, 2023

Hi @unix1234 ,

I currently use a solution that polls the web interface on the inverter, instead of relying on the server options on the inverter.

I made a small write-up on how I set it up on my blog: https://teeffelen.gitlab.io/blog/omnik-data-logging

@unix1234
Copy link

Hi @unix1234 ,

I currently use a solution that polls the web interface on the inverter, instead of relying on the server options on the inverter.

I made a small write-up on how I set it up on my blog: https://teeffelen.gitlab.io/blog/omnik-data-logging

Hi, thank you for the suggestion, but my inverter does not have the JSON file.
I only get the following buffer via TCP-Request on Port 8899: [165,1,0,16,71,253,23,154,136,68,250,0,204,21]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment