Omnik Export Script

Topics (not sure which fora)
when not sure where to post, post here and mods will move it to right forum.

Moderators: leecollings, remb0

Noppie
Posts: 7
Joined: Friday 19 February 2016 15:50
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Omnik Export Script

Post by Noppie »

Can anybody help me:

I used the script form the wiki Omnik Inverter, but I keep getting errors when I run the script.

traceback (most recent call last):
File "OmnikMessage.py", line 83, in <module>
s.sendall(InverterMsg.generate_string(wifi_serial))
AttributeError: 'module' object has no attribute 'generate_string'

I'm a newbie so it's difficult for me.

Thanx!
edsirtan
Posts: 2
Joined: Saturday 26 March 2016 15:35
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Omnik Export Script

Post by edsirtan »

Hello Noppy, I'm also struggling to solve this issue. Do you have al solution yet?
I do get the same error when using the OmikExport script:

pi@raspberrypi:~/domoticz/Omnik-Data-Logger$ python OmnikExport.py
Traceback (most recent call last):
File "OmnikExport.py", line 83, in <module>
s.sendall(InverterMsg.generate_string(wifi_serial))
AttributeError: 'module' object has no attribute 'generate_string'
pi@raspberrypi:

Probably something to do with the generate_string not able to find in the script.

Can anybody help????

Thnx
User avatar
sincze
Posts: 1299
Joined: Monday 02 June 2014 22:46
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.4
Location: Netherlands / Breda Area
Contact:

Re: Omnik Export Script

Post by sincze »

Can you share the first 3 digits of the serial number of the Omnik inverter?
It seems the script is not always working for all the Omnik inverters.
Pass2php
LAN: RFLink, P1, OTGW, MySensors
USB: RFXCom, ZWave, Sonoff 3
MQTT: ZIgbee2MQTT,
ZWAVE: Zwave-JS-UI
WIFI: Mi-light, Tasmota, Xiaomi Shelly
Solar: Omnik, PVOutput
Video: Kodi, Harmony HUB, Chromecast
Sensors: You name it I got 1.
jbr79
Posts: 20
Joined: Saturday 17 October 2015 22:23
Target OS: Linux
Domoticz version: 4.10659
Contact:

Re: Omnik Export Script

Post by jbr79 »

Also struggling with this particular script. :cry:

Since LiveStats.py is functioning properly (generating output), I am not expecting that the following error:

Code: Select all

Traceback (most recent call last):
  File "Omnik-Export.py", line 83, in <module>
    s.sendall(InverterMsg.generate_string(wifi_serial))
AttributeError: 'module' object has no attribute 'generate_string'
....has anything to do with the device serial number, but rather with the python configuration (more specifically the InverterMsg.py file)

I am running python version 2.7.9 on a RBPi3.
Last edited by jbr79 on Wednesday 30 March 2016 15:33, edited 1 time in total.
User avatar
sincze
Posts: 1299
Joined: Monday 02 June 2014 22:46
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.4
Location: Netherlands / Breda Area
Contact:

Re: Omnik Export Script

Post by sincze »

That would have been indeed my next question. :D

It is known that Omnik Export script doesn't work for all Omnik Inverter.
However if LiveStats is producing output... the rest should work for you as well.

Mine is on Python version 2.7.3.

Code: Select all

root@PC:/home/domoticz/Omnik-Data-Logger# python OmnikExport.py
root@PC:/home/domoticz/Omnik-Data-Logger#
I copy pasted the script from the wiki into a temp.py file and executed that one. No Errors.
The code in the wiki is still okay.

Have to keep digging some more.
Pass2php
LAN: RFLink, P1, OTGW, MySensors
USB: RFXCom, ZWave, Sonoff 3
MQTT: ZIgbee2MQTT,
ZWAVE: Zwave-JS-UI
WIFI: Mi-light, Tasmota, Xiaomi Shelly
Solar: Omnik, PVOutput
Video: Kodi, Harmony HUB, Chromecast
Sensors: You name it I got 1.
jbr79
Posts: 20
Joined: Saturday 17 October 2015 22:23
Target OS: Linux
Domoticz version: 4.10659
Contact:

Re: Omnik Export Script

Post by jbr79 »

I copy pasted the script from the wiki into a temp.py file and executed that one. No Errors.
The code in the wiki is still okay.
Curious: I had to do several adjustments to align the variable names in the config.cfg file (which was pulled in via a Git clone of the source files - git clone https://github.com/Woutrrr/Omnik-Data-Logger.git) and the Omnik-export.py (the code in the wiki) file.

Were you able to use both files without adjustment?
User avatar
sincze
Posts: 1299
Joined: Monday 02 June 2014 22:46
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.4
Location: Netherlands / Breda Area
Contact:

Re: Omnik Export Script

Post by sincze »

you got me there. :D
I did not overwrite the .cfg file indeed. I used my original one.

Code: Select all

################
### Settings ###
################

[inverter]
# IP address of your Omnik inverter
ip = ***.***.***.***
# Default for a Omnik with Wifi module
port = 8899
# S/N of the wifi kit
wifi_sn = 1602******
#use temperature of inverter for pvoutput
use_temperature = true

[mysql]
# Enable for exporting to a mysql database
mysql_enabled = false           
# Host where the mysql server is active
mysql_host = 127.0.0.1        
mysql_user =    
mysql_pass =             
mysql_db   =             


[domoticz]
domoticz_enabled   = true
domoticz_host 	   = ***.***.***.***
domoticz_port 	   = 8080
domoticz_url  	   = json.htm
# Provide IDX here of the specific devices
domoticz_temp 	   = ***
domoticz_Input_PV1 = ***
domoticz_Input_PV2 = ***
domoticz_AC_Output = ***
domoticz_Cur_Total = ***
domoticz_AMP_1_2_3 = *** 

[pvout]
# Enable or disable uploading to PVoutput
pvout_enabled =false
# These two can be found at http://pvoutput.org/account.jsp
pvout_apikey = NOTAREALAPIKEY86e2258d4e29169fb79cf18b00 
pvout_sysid  = 12345

[log]
log_enabled  = true
log_filename = omnik-export.log
Pass2php
LAN: RFLink, P1, OTGW, MySensors
USB: RFXCom, ZWave, Sonoff 3
MQTT: ZIgbee2MQTT,
ZWAVE: Zwave-JS-UI
WIFI: Mi-light, Tasmota, Xiaomi Shelly
Solar: Omnik, PVOutput
Video: Kodi, Harmony HUB, Chromecast
Sensors: You name it I got 1.
jbr79
Posts: 20
Joined: Saturday 17 October 2015 22:23
Target OS: Linux
Domoticz version: 4.10659
Contact:

Re: Omnik Export Script

Post by jbr79 »

I see you disabled mysql and pv_output - I am wondering if that might change the outcome
I will try this evening.
User avatar
sincze
Posts: 1299
Joined: Monday 02 June 2014 22:46
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.4
Location: Netherlands / Breda Area
Contact:

Re: Omnik Export Script

Post by sincze »

Jups. I don't use MYSQL to separately store the data, so disabled it.
I enabled PVOutput "true" and data is now being exported to PVOutput. Works nicely. :D

Normally I would have used the wiki for PVOutput upload, but since daylight save change that does not work for me anymore.
http://www.domoticz.com/wiki/Upload_ene ... o_PVoutput :roll:
Did not yet figure out why. I do recveive the correct data, however PVOutput doesn't seem to like it anymore.

Code: Select all

2016-03-29 23:25:00.770 LUA: ---- The total generated energy is 14310.0 Wh
2016-03-29 23:25:00.770 LUA: ---- The current generated power is 0 W
2016-03-29 23:25:00.770 LUA: ---- The voltage of the inverter is 0.0 V
2016-03-29 23:25:00.770 LUA: ---- The outside temperature is 9.1 C.
2016-03-29 23:25:00.770 LUA: ---- The total consumed energy is 10761371 Wh
2016-03-29 23:25:00.770 LUA: ---- The current consumed power is 650 W
A well back to the original topic. I issued a python3 command..

Code: Select all

root@PC:/home/domoticz/Omnik-Data-Logger# python3 LiveStats.py
  File "LiveStats.py", line 52
    print 'could not open socket'
                                ^
SyntaxError: invalid syntax

root@PC:/home/domoticz/Omnik-Data-Logger# python LiveStats.py

Code: Select all

connecting to ***.***.***.*** port 8899
ID: NL**************
E Today: 14.03   Total: 6623.6
H Total:     0   Temp:  38.5
PV1   V: 268.6   I:  3.0
PV2   V: 266.4   I:  3.0
PV3   V:   0.0   I:  0.0
L1    P:  1424   V: 238.8   I:  5.9   F:  50.0
L2    P:     0   V:   0.0   I:  0.0   F:   0.0
L3    P:     0   V:   0.0   I:  0.0   F:   0.0
So some errors do occur when using a different python version.
At least so it seams....
Regular python is version: Python 2.7.3, can you try that one as well?
Pass2php
LAN: RFLink, P1, OTGW, MySensors
USB: RFXCom, ZWave, Sonoff 3
MQTT: ZIgbee2MQTT,
ZWAVE: Zwave-JS-UI
WIFI: Mi-light, Tasmota, Xiaomi Shelly
Solar: Omnik, PVOutput
Video: Kodi, Harmony HUB, Chromecast
Sensors: You name it I got 1.
jbr79
Posts: 20
Joined: Saturday 17 October 2015 22:23
Target OS: Linux
Domoticz version: 4.10659
Contact:

Re: Omnik Export Script

Post by jbr79 »

I know from my previous encounter with Python that Python3 is a different ballgame. Anyway, having access to the file contents now that it is evening, disabling mysql and pvoutput obviously did not do the trick.

I am however curious as to what the contents of your InverterMsg.py file is. Mine does not hold any reference to 'generate_string'. With my limited programming experience I would say there is another clue hidden in that file.
User avatar
sincze
Posts: 1299
Joined: Monday 02 June 2014 22:46
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.4
Location: Netherlands / Breda Area
Contact:

Re: Omnik Export Script

Post by sincze »

Line 78 generate_string of the file InverterMsg.py

Code: Select all

import struct               # Converting bytes to numbers

class InverterMsg:
    'Class for Inverter message'
    rawmsg = ""
    
    def __init__(self, msg, offset=0):
        self.rawmsg = msg
        self.offset = offset
        
    def __getString(self, begin, end):
        return self.rawmsg[begin:end]
    
    def __getShort(self, begin, devider=10):
        num = struct.unpack('!H', self.rawmsg[begin:begin+2])[0]
        if num == 65535:
            return -1
        else:
            return float(num)/devider
        
    def __getLong(self, begin, devider=10):
        return float(struct.unpack('!I', self.rawmsg[begin:begin+4])[0])/devider
        
    def getID(self):
        return self.__getString(15,31)

    def getTemp(self):
        return self.__getShort(31)
    
    def getPower(self):
        print self.__getShort(59)
        
    def getETotal(self):
        return self.__getLong(71)
        
    def getVPV(self, i=1):
        if i  not in range(1, 4):
            i = 1
        num = 33 + (i-1)*2
        return self.__getShort(num)
        
    def getIPV(self, i=1):
        if i not in range(1, 4):
            i=1
        num = 39 + (i-1)*2
        return self.__getShort(num)
    
    def getIAC(self, i=1):
        if i not in range(1, 4):
            i=1
        num = 45 + (i-1)*2
        return self.__getShort(num)
        
    def getVAC(self, i=1):
        if i not in range(1, 4):
            i=1
        num = 51 + (i-1)*2
        return self.__getShort(num)  

    def getFAC(self, i=1):
        if i not in range(1, 4):
            i=1
        num = 57 + (i-1)*4
        return self.__getShort(num, 100)          

    def getPAC(self, i=1):
        if i not in range(1, 4):
            i=1
        num = 59 + (i-1)*4
        return int(self.__getShort(num, 1)) # Don't divide
    
    def getEToday(self):
        return self.__getShort(69, 100)     # Devide by 100

    def getHTotal(self):
        return int(self.__getLong(75, 1))  # Don't divide

def generate_string(ser):
    '''
    The request string is build from several parts. The first part is a
    fixed 4 char string; the second part is the reversed hex notation of
    the s/n twice; then again a fixed string of two chars; a checksum of
    the double s/n with an offset; and finally a fixed ending char.
    '''
    responseString = '\x68\x02\x40\x30';

    doublehex = hex(ser)[2:]*2
    hexlist = [ doublehex[i:i+2].decode('hex') for i in 
        reversed(range(0, len(doublehex), 2))]

    cs_count = 115 + sum([ ord(c) for c in hexlist])
    cs = hex(cs_count)[-2:].decode('hex')
    responseString += ''.join(hexlist) + '\x01\x00'+cs+'\x16'
    return responseString
Pass2php
LAN: RFLink, P1, OTGW, MySensors
USB: RFXCom, ZWave, Sonoff 3
MQTT: ZIgbee2MQTT,
ZWAVE: Zwave-JS-UI
WIFI: Mi-light, Tasmota, Xiaomi Shelly
Solar: Omnik, PVOutput
Video: Kodi, Harmony HUB, Chromecast
Sensors: You name it I got 1.
jbr79
Posts: 20
Joined: Saturday 17 October 2015 22:23
Target OS: Linux
Domoticz version: 4.10659
Contact:

Re: Omnik Export Script

Post by jbr79 »

Is that the entire contents?

Mine is different (see below).Where did you get your file from?

pi@raspberrypi:~/Omnik-Data-Logger $ cat InverterMsg.py

Code: Select all

import struct  # Converting bytes to numbers

class InverterMsg(object):
    """Decode the response message from an omniksol inverter."""
    raw_msg = ""

    def __init__(self, msg, offset=0):
        self.raw_msg = msg
        self.offset = offset

    def __get_string(self, begin, end):
        """Extract string from message.

        Args:
            begin (int): starting byte index of string
            end (int): end byte index of string

        Returns:
            str: String in the message from start to end
        """
        return self.raw_msg[begin:end]

    def __get_short(self, begin, divider=10):
        """Extract short from message.

        The shorts in the message could actually be a decimal number. This is
        done by storing the number multiplied in the message. So by dividing
        the short the original decimal number can be retrieved.

        Args:
            begin (int): index of short in message
            divider (int): divider to change short to float. (Default: 10)

        Returns:
            int or float: Value stored at location `begin`
        """
        num = struct.unpack('!H', self.raw_msg[begin:begin + 2])[0]
        if num == 65535:
            return -1
        else:
            return float(num) / divider

    def __get_long(self, begin, divider=10):
        """Extract long from message.

        The longs in the message could actually be a decimal number. By
        dividing the long, the original decimal number can be extracted.

        Args:
            begin (int): index of long in message
            divider (int): divider to change long to float. (Default : 10)

        Returns:
            int or float: Value stored at location `begin`
        """
        return float(
            struct.unpack('!I', self.raw_msg[begin:begin + 4])[0]) / divider

    @property
    def id(self):
        """ID of the inverter."""
        return self.__get_string(15, 31)

    @property
    def temperature(self):
        """Temperature recorded by the inverter."""
        return self.__get_short(31)

    @property
    def power(self):
        """Power output"""
        print self.__get_short(59)

    @property
    def e_total(self):
        """Total energy generated by inverter in kWh"""
        return self.__get_long(71)

    def v_pv(self, i=1):
        """Voltage of PV input channel.

        Available channels are 1, 2 or 3; if not in this range the function will
        default to channel 1.

        Args:
            i (int): input channel (valid values: 1, 2, 3)

        Returns:
            float: PV voltage of channel i
        """
        if i not in range(1, 4):
            i = 1
        num = 33 + (i - 1) * 2
        return self.__get_short(num)

    def i_pv(self, i=1):
        """Current of PV input channel.

        Available channels are 1, 2 or 3; if not in this range the function will
        default to channel 1.

        Args:
            i (int): input channel (valid values: 1, 2, 3)

        Returns:
            float: PV current of channel i
        """
        if i not in range(1, 4):
            i = 1
        num = 39 + (i - 1) * 2
        return self.__get_short(num)

    def i_ac(self, i=1):
        """Current of the Inverter output channel

        Available channels are 1, 2 or 3; if not in this range the function will
        default to channel 1.

        Args:
            i (int): output channel (valid values: 1, 2, 3)

        Returns:
            float: AC current of channel i

        """
        if i not in range(1, 4):
            i = 1
        num = 45 + (i - 1) * 2
        return self.__get_short(num)

    def v_ac(self, i=1):
        """Voltage of the Inverter output channel

        Available channels are 1, 2 or 3; if not in this range the function will
        default to channel 1.

        Args:
            i (int): output channel (valid values: 1, 2, 3)

        Returns:
            float: AC voltage of channel i
        """
        if i not in range(1, 4):
            i = 1
        num = 51 + (i - 1) * 2
        return self.__get_short(num)

    def f_ac(self, i=1):
        """Frequency of the output channel

        Available channels are 1, 2 or 3; if not in this range the function will
        default to channel 1.

        Args:
            i (int): output channel (valid values: 1, 2, 3)

        Returns:
            float: AC frequency of channel i
        """
        if i not in range(1, 4):
            i = 1
        num = 57 + (i - 1) * 4
        return self.__get_short(num, 100)

    def p_ac(self, i=1):
        """Power output of the output channel

        Available channels are 1, 2 or 3; if no tin this range the function will
        default to channel 1.

        Args:
            i (int): output channel (valid values: 1, 2, 3)

        Returns:
            float: Power output of channel i
        """
        if i not in range(1, 4):
            i = 1
        num = 59 + (i - 1) * 4
        return int(self.__get_short(num, 1))  # Don't divide

    @property
    def e_today(self):
        """Energy generated by inverter today in kWh"""
        return self.__get_short(69, 100)  # Divide by 100

    @property
    def h_total(self):
        """Hours the inverter generated electricity"""
        return int(self.__get_long(75, 1))  # Don't divide
User avatar
sincze
Posts: 1299
Joined: Monday 02 June 2014 22:46
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.4
Location: Netherlands / Breda Area
Contact:

Re: Omnik Export Script

Post by sincze »

Euh indeed that is my entire content :shock: of my document indeed.
However it seems to work.

Maybe exchange yours for mine and see what happens ??
Pass2php
LAN: RFLink, P1, OTGW, MySensors
USB: RFXCom, ZWave, Sonoff 3
MQTT: ZIgbee2MQTT,
ZWAVE: Zwave-JS-UI
WIFI: Mi-light, Tasmota, Xiaomi Shelly
Solar: Omnik, PVOutput
Video: Kodi, Harmony HUB, Chromecast
Sensors: You name it I got 1.
jbr79
Posts: 20
Joined: Saturday 17 October 2015 22:23
Target OS: Linux
Domoticz version: 4.10659
Contact:

Re: Omnik Export Script

Post by jbr79 »

That would have been too easy; failure at first sight:
pi@RPi3:~/domoticz/scripts/python/Omnik-Data-Logger $ python LiveStats.py
Traceback (most recent call last):
File "LiveStats.py", line 7, in <module>
import OmnikExport
ImportError: No module named OmnikExport
I saw there was a staticmethod available in the original OmnikExport.py module. Tried copying that to the InverterMSg.py file, but without success. Same error message:

Code: Select all

pi@RPi3:~/domoticz/scripts/python/Omnik-Data-Logger $ python Export.py
Traceback (most recent call last):
  File "Export.py", line 83, in <module>
    s.sendall(InverterMsg.generate_string(wifi_serial))
AttributeError: 'module' object has no attribute 'generate_string'


I did not get around to interchanging the generate_string def from your file pasted above with my own InverterMsg.py - will have to find time somewhere this weekend.
jbr79
Posts: 20
Joined: Saturday 17 October 2015 22:23
Target OS: Linux
Domoticz version: 4.10659
Contact:

Re: Omnik Export Script

Post by jbr79 »

Seems there is a lot more to be done to get this script up and running. I find myself replacing one function after another, but without success. It keeps producing a new error every time. Call me naive, but I fail to see why there seem to be two versions of the same file out in the open. One being completely incompatible.
edsirtan
Posts: 2
Joined: Saturday 26 March 2016 15:35
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Omnik Export Script

Post by edsirtan »

I also was struggling to get this InverterMsg.py working. I am not a programmer merely I cutted, pasted, trial and errored a lot and I have now a working solution for my situation. Maybe someone with more python skills can make it work for all situations, because with this script the Livestats do not work anymore. In short I added the config of the old file in the new one
And the virtual sensors are now filled with data.

Code: Select all

pi@raspberrypi:~/domoticz/Omnik-Data-Logger$ cat InverterMsg.py
import struct  # Converting bytes to numbers


class InverterMsg(object):
    """Decode the response message from an omniksol inverter."""
    raw_msg = ""

    def __init__(self, msg, offset=0):
        self.raw_msg = msg
        self.offset = offset

    def __get_string(self, begin, end):
        """Extract string from message.

        Args:
            begin (int): starting byte index of string
            end (int): end byte index of string

        Returns:
            str: String in the message from start to end
        """
        return self.raw_msg[begin:end]

    def __get_short(self, begin, divider=10):
        """Extract short from message.

        The shorts in the message could actually be a decimal number. This is
        done by storing the number multiplied in the message. So by dividing
        the short the original decimal number can be retrieved.

        Args:
            begin (int): index of short in message
            divider (int): divider to change short to float. (Default: 10)

        Returns:
            int or float: Value stored at location `begin`
        """
        num = struct.unpack('!H', self.raw_msg[begin:begin + 2])[0]
        if num == 65535:
            return -1
        else:
            return float(num) / divider

    def __get_long(self, begin, divider=10):
        """Extract long from message.

        The longs in the message could actually be a decimal number. By
        dividing the long, the original decimal number can be extracted.

        Args:
            begin (int): index of long in message
            divider (int): divider to change long to float. (Default : 10)

        Returns:
            int or float: Value stored at location `begin`
        """
        return float(
            struct.unpack('!I', self.raw_msg[begin:begin + 4])[0]) / divider

    @property
    def id(self):
        """ID of the inverter."""
        return self.__get_string(15, 31)

    @property
    def temperature(self):
        """Temperature recorded by the inverter."""
        return self.__get_short(31)

    @property
    def power(self):
        """Power output"""
        print self.__get_short(59)

    @property
    def e_total(self):
        """Total energy generated by inverter in kWh"""
        return self.__get_long(71)

    def v_pv(self, i=1):
        """Voltage of PV input channel.

        Available channels are 1, 2 or 3; if not in this range the function will
        default to channel 1.

        Args:
            i (int): input channel (valid values: 1, 2, 3)

        Returns:
            float: PV voltage of channel i
        """
        if i not in range(1, 4):
            i = 1
        num = 33 + (i - 1) * 2
        return self.__get_short(num)

    def i_pv(self, i=1):
        """Current of PV input channel.

        Available channels are 1, 2 or 3; if not in this range the function will
        default to channel 1.

        Args:
            i (int): input channel (valid values: 1, 2, 3)

        Returns:
            float: PV current of channel i
        """
        if i not in range(1, 4):
            i = 1
        num = 39 + (i - 1) * 2
        return self.__get_short(num)

    def i_ac(self, i=1):
        """Current of the Inverter output channel

        Available channels are 1, 2 or 3; if not in this range the function will
        default to channel 1.

        Args:
            i (int): output channel (valid values: 1, 2, 3)

        Returns:
            float: AC current of channel i

        """
        if i not in range(1, 4):
            i = 1
        num = 45 + (i - 1) * 2
        return self.__get_short(num)

    def v_ac(self, i=1):
        """Voltage of the Inverter output channel

        Available channels are 1, 2 or 3; if not in this range the function will
        default to channel 1.

        Args:
            i (int): output channel (valid values: 1, 2, 3)

        Returns:
            float: AC voltage of channel i
        """
        if i not in range(1, 4):
            i = 1
        num = 51 + (i - 1) * 2
        return self.__get_short(num)

    def f_ac(self, i=1):
        """Frequency of the output channel

        Available channels are 1, 2 or 3; if not in this range the function will
        default to channel 1.

        Args:
            i (int): output channel (valid values: 1, 2, 3)

        Returns:
            float: AC frequency of channel i
        """
        if i not in range(1, 4):
            i = 1
        num = 57 + (i - 1) * 4
        return self.__get_short(num, 100)

    def p_ac(self, i=1):
        """Power output of the output channel

        Available channels are 1, 2 or 3; if no tin this range the function will
        default to channel 1.

        Args:
            i (int): output channel (valid values: 1, 2, 3)

        Returns:
            float: Power output of channel i
        """
        if i not in range(1, 4):
            i = 1
        num = 59 + (i - 1) * 4
        return int(self.__get_short(num, 1))  # Don't divide

    @property
    def e_today(self):
        """Energy generated by inverter today in kWh"""
        return self.__get_short(69, 100)  # Divide by 100

    @property
    def h_total(self):
        """Hours the inverter generated electricity"""
        return int(self.__get_long(75, 1))  # Don't divide


    def __init__(self, msg, offset=0):
        self.rawmsg = msg
        self.offset = offset
       
    def __getString(self, begin, end):
        return self.rawmsg[begin:end]
   
    def __getShort(self, begin, devider=10):
        num = struct.unpack('!H', self.rawmsg[begin:begin+2])[0]
        if num == 65535:
            return -1
        else:
            return float(num)/devider
       
    def __getLong(self, begin, devider=10):
        return float(struct.unpack('!I', self.rawmsg[begin:begin+4])[0])/devider

    def getID(self):
        return self.__getString(15,31)

    def getTemp(self):
        return self.__getShort(31)
   
    def getPower(self):
        print self.__getShort(59)
       
    def getETotal(self):
        return self.__getLong(71)
       
    def getVPV(self, i=1):
        if i  not in range(1, 4):
            i = 1
        num = 33 + (i-1)*2
        return self.__getShort(num)
       
    def getIPV(self, i=1):
        if i not in range(1, 4):
            i=1
        num = 39 + (i-1)*2
        return self.__getShort(num)
   
    def getIAC(self, i=1):
        if i not in range(1, 4):
            i=1
        num = 45 + (i-1)*2
        return self.__getShort(num)
       
    def getVAC(self, i=1):
        if i not in range(1, 4):
            i=1
        num = 51 + (i-1)*2
        return self.__getShort(num) 

    def getFAC(self, i=1):
        if i not in range(1, 4):
            i=1
        num = 57 + (i-1)*4
        return self.__getShort(num, 100)         

    def getPAC(self, i=1):
        if i not in range(1, 4):
            i=1
        num = 59 + (i-1)*4
        return int(self.__getShort(num, 1)) # Don't divide
   
    def getEToday(self):
        return self.__getShort(69, 100)     # Devide by 100

    def getHTotal(self):
        return int(self.__getLong(75, 1))  # Don't divide


def generate_string(ser):
    '''
    The request string is build from several parts. The first part is a
    fixed 4 char string; the second part is the reversed hex notation of
    the s/n twice; then again a fixed string of two chars; a checksum of
    the double s/n with an offset; and finally a fixed ending char.
    '''
    responseString = '\x68\x02\x40\x30';





    doublehex = hex(ser)[2:]*2
    hexlist = [ doublehex[i:i+2].decode('hex') for i in
        reversed(range(0, len(doublehex), 2))]





    cs_count = 115 + sum([ ord(c) for c in hexlist])
    cs = hex(cs_count)[-2:].decode('hex')
    responseString += ''.join(hexlist) + '\x01\x00'+cs+'\x16'
    return responseString

jbr79
Posts: 20
Joined: Saturday 17 October 2015 22:23
Target OS: Linux
Domoticz version: 4.10659
Contact:

Re: Omnik Export Script

Post by jbr79 »

@sincze: would you be able to share your InverterMsg.py , Export.py and LiveStats.py files?
( or for that matter, your anonimized folder) I wonder if I have any luck with them instead of trying to alter my current ones.
User avatar
sincze
Posts: 1299
Joined: Monday 02 June 2014 22:46
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.4
Location: Netherlands / Breda Area
Contact:

Re: Omnik Export Script

Post by sincze »

No Problem.
Please find attached the files you requested.
Let me know the results please :D
Attachments
OmnikExport.py.txt
OmnikExport.py
(8.63 KiB) Downloaded 144 times
LiveStats.py.txt
LiveStats.py
(3.17 KiB) Downloaded 130 times
InverterMsg.py.txt
InverterMsg.py
(2.63 KiB) Downloaded 130 times
Pass2php
LAN: RFLink, P1, OTGW, MySensors
USB: RFXCom, ZWave, Sonoff 3
MQTT: ZIgbee2MQTT,
ZWAVE: Zwave-JS-UI
WIFI: Mi-light, Tasmota, Xiaomi Shelly
Solar: Omnik, PVOutput
Video: Kodi, Harmony HUB, Chromecast
Sensors: You name it I got 1.
jbr79
Posts: 20
Joined: Saturday 17 October 2015 22:23
Target OS: Linux
Domoticz version: 4.10659
Contact:

Re: Omnik Export Script

Post by jbr79 »

FINALLY: SUCCESS!!!

Big Thanks goes out to sincze for sharing the files! :D The solution was not in them alone, but they got me started.

So we've established there were differences in the python files. My starting point was that I could get LiveStats.py to work perfectly in console, but OmnikExport.py would generate new errors every time (so you fix, you fall right in the other).
I found out there are two isolated incidents:
- first, the git cloned files have different function names (especially in InverterMsg.py)
- there is (was - I corrected it to prevent more grey hair) an awfully crappy error in the instructions on the Wiki. The config file holds an extra space that is preventing the correct encoding of the URL! :shock:
Image

My final solution:
  • git clone the files from git clone https://github.com/Woutrrr/Omnik-Data-Logger.git
  • generate the config.cfg file with my settings, and add the lines from the config in the wiki
  • test the LiveStats.py file. This should generate output (otherwise it won't work at all with your Converter)
  • Create a file called Export.py with the contents of the instructions for the OmnikExport.py file on the wiki, but initially also added "import OmnikExport" at the top (this was removed later)
  • used the InverterMsg.py file from sincze to copy all missing code (so what is not originally in the git clone)
  • do a a little cleanup of the InverterMsg.py file. There's functions that expect for example getString while it is called get_string in the file.
Keep checking after each edit that LiveStats.py is still working and run Export.py.

I can't believe it actually works! :)
User avatar
sincze
Posts: 1299
Joined: Monday 02 June 2014 22:46
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.4
Location: Netherlands / Breda Area
Contact:

Re: Omnik Export Script

Post by sincze »

:D :D :D :D :D :D
Nice work.

You updated the wiki as well. tnx.
This will avoid grey hairs for other people.
Pass2php
LAN: RFLink, P1, OTGW, MySensors
USB: RFXCom, ZWave, Sonoff 3
MQTT: ZIgbee2MQTT,
ZWAVE: Zwave-JS-UI
WIFI: Mi-light, Tasmota, Xiaomi Shelly
Solar: Omnik, PVOutput
Video: Kodi, Harmony HUB, Chromecast
Sensors: You name it I got 1.
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest