Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

modbus_init, Luxtronic2 reconnect and pack/unpack and smartvisu type error #210

Open
wants to merge 12 commits into
base: develop
Choose a base branch
from

Conversation

kr2
Copy link

@kr2 kr2 commented Apr 25, 2017

modbus_init: readme
Luxtronic2: readme

The count string handed from smartvisu was not casted to int.

@@ -46,6 +56,12 @@ Defines a mapping to a attribute (read-only). All attribute values are bytes (nu
### lux2_c
Defines a mapping to a calculated value (read-only). All calculated values are integer (numbers).

### lux2_unpack
Python lambda function. Called before the value is sent towards the device.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The unpack option sounds like the common eval setting for items. It evaluates the value and puts the result into the item. IMHO, I prefer to use common settings instead of having special plugin settings for all the plugins.


### lux2_pack
Called before the value is written to the smarthome item.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could also be a common setting for items - something like eval_out - which works like eval, but the other way around when item is set.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see your point and I thought about it too. Something like eval_out would work most of the time, but it would fail for something like the example below. My thinking is that a plugin should provide you with a ready to use value and the other way around should take the unencoded value. E.g. for the knx plugin you have to provide knx_dpt and the plugin handles pack/unpack stuff.
First I only created *_pack for something like below and the way I think of plugins and I did *_unpack out of symmetry. E.g. one could use *_unpack to do the word/byte/... decoding stuff and eval for some value transformation (seconds to days).
I can make the *_pack and *_unpack optional, populated to hand the values through, but I would like to keep them.

 [[[dp1]]]
      type = num
      knx_dpt = 9
      knx_send = 10/4/8
      modbus_addr = Blub1 | 1 | 9 | 1
      modbus_type = HoldingRegister
      modbus_readInterval = -1
      modbus_pack = lambda x: [int((x * 1023) / 102.3)]

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ohinckel I looked a bit further into default values for modbus_pack (same for unpack and lux2).
I still don't see a good way for eval_out. To make something like my last example work, it would have to check the caller e.g. like: eval_out = return knxVal if caller == 'KNX' else return modbusVal
I gonna stick with pack(/unpack), if you don't have a better solution.
The somewhat defaults at the moment are lambda x: x. I think this means one does not have to use the pack/unpack functions if the type is set to list. If *_pack is used it could be any other type and it should be possible to use eval for unpacking. I did not test that.
So again I don't see any better way.

# fail in this application, because it calles the foo without checking
# if the last call finished. This could clog up the system.
threading.Thread(name='Lux2_cycle', target=self.__refresh).start()
threading.Thread(name='Lux2_recon', target=self._reconnect).start()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there really cases were the update cylce needs too much time? Maybe using a short timeout for querying the device could help here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See also my bug report for that. For now, it works with threading, but I could not get it working with the scheduler. I don't think it is about the socket timeout, because I also had problems with the scheduler in the modbus plugin too.

@@ -328,22 +399,44 @@ def _decode(self, identifier, value):
return value

def parse_item(self, item):
def __reverseListOp(param):
# reversing list building of smarthome.py config parser for the
# binary or opperator |

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think putting the value in quotes will fix this problem too. Usually you should be using quotes around the value to avoid escaping problem.

Other setting may have this problem too, but we should not start to implement such an "unquoting mechanism" for each of these settings. A general solution, which already exists (using quotes), would be more clear and consistent.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not know that quotes are supported, but if it works it's most definitely a better way to do it. I am going to fix it when there is time for it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ohinckel I just check the config parser again and quotes are not supported right now. I also tried it and there is no magic gunk happening somewhere else.

config.py line:89...

attr, __, value = line.partition('=')
...
attr = attr.strip()
...
if '|' in value:
    item[attr] = [strip_quotes(x) for x in value.split('|')]
else:
    item[attr] = strip_quotes(value)

So to allow list operators in combination with quotes, it would have to ignore pipes inside of quotes and split if there are pips outside of them. I did a quick hack, see below. If you have a better solution or if I missed something let me know.

def split_pipe(s):
    output = []
    split_pos = []
    quotes = ['"',"'"]
    pipe = '|'
    in_quoate = False
    start_quote = None
    
    for i in range(0, len(s)):
        if not in_quoate and s[i] == pipe:
            split_pos.append(i)
        
        if not in_quoate and s[i] in quotes:
            start_quote = s[i]
            in_quoate = True  
        elif in_quoate and s[i] == start_quote:
            in_quoate = False
            
    if len(split_pos) > 0:      
        output.append(s[0:split_pos[0]])
        for i in range(0,len(split_pos)):
            if i+1 < len(split_pos):
                output.append(s[split_pos[i]+1:split_pos[i+1]])
            else:
                output.append(s[split_pos[i]+1:])
        output = [strip_quotes(x) for x in output]
        return output
    else:
        return strip_quotes(s)

s = """'123|456'|"789'10'|1112"|131415 """

current = [strip_quotes(x) for x in s.split('|')]
for i in current:
    print(i)
print('-'*10)
x = split_pipe(s)
for i in x:
    print(i)
print('-'*10)
x = split_pipe('1')
print(x)

kr2 added 3 commits May 2, 2017 08:38
Added some debug gunk. Verbose output option, status for each master in var/modbus/*.txt, ...
Added random start time for reads to even out load
@kr2
Copy link
Author

kr2 commented May 3, 2017

Commit 8e29643 will fix #209

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants