@@ -586,8 +586,85 @@ def get_dt(bytearray_: bytearray, byte_index: int) -> str:
586586 return date_and_time
587587
588588
589+ def get_time (bytearray_ : bytearray , byte_index : int ) -> str :
590+ """Get time value from bytearray.
591+
592+ Notes:
593+ Datatype `time` consists in 4 bytes in the PLC.
594+ Maximum possible value is T#24D_20H_31M_23S_647MS(2147483647).
595+ Lower posible value is T#-24D_20H_31M_23S_648MS(-2147483648).
596+
597+ Args:
598+ bytearray_: buffer to read.
599+ byte_index: byte index from where to start reading.
600+
601+ Returns:
602+ Value read.
603+
604+ Examples:
605+ >>> import struct
606+ >>> data = bytearray(4)
607+ >>> data[:] = struct.pack(">i", 2147483647)
608+ >>> snap7.util.get_time(data, 0)
609+ '24:20:31:23:647'
610+ """
611+ data_bytearray = bytearray_ [byte_index :byte_index + 4 ]
612+ bits = 32
613+ sign = 1
614+ byte_str = data_bytearray .hex ()
615+ val = int (byte_str , 16 )
616+ if (val & (1 << (bits - 1 ))) != 0 :
617+ sign = - 1 # if sign bit is set e.g., 8bit: 128-255
618+ val = val - (1 << bits ) # compute negative value
619+ val = val * sign
620+
621+ milli_seconds = val % 1000
622+ seconds = val // 1000
623+ minutes = seconds // 60
624+ hours = minutes // 60
625+ days = hours // 24
626+ time_str = str (days * sign ) + ":" + str (hours % 24 ) + ":" + str (minutes % 60 ) + ":" + str (seconds % 60 ) + "." + str (milli_seconds )
627+ return time_str
628+
629+
630+ def set_time (bytearray_ : bytearray , byte_index : int , time_string : str ) -> bytearray :
631+ """Set value in bytearray to time
632+
633+ Notes:
634+ Datatype `time` consists in 4 bytes in the PLC.
635+ Maximum possible value is T#24D_20H_31M_23S_647MS(2147483647).
636+ Lower posible value is T#-24D_20H_31M_23S_648MS(-2147483648).
637+
638+ Args:
639+ bytearray_: buffer to write.
640+ byte_index: byte index from where to start writing.
641+ time_string: time value in string
642+
643+ Examples:
644+ >>> data = bytearray(4)
645+ >>> snap7.util.set_dint(data, 0, '-22:3:57:28.192')
646+ >>> data
647+ bytearray(b'\x8d \xda \xaf \x00 ')
648+ """
649+ import re
650+ sign = 1
651+ bits = 32
652+ data_list = re .split ('[: .]' , time_string )
653+ days , hours , minutes , seconds , milli_seconds = [int (x ) for x in data_list ]
654+ if days < 0 :
655+ sign = - 1
656+ time_int = ((days * sign * 3600 * 24 + (hours % 24 ) * 3600 + (minutes % 60 ) * 60 + seconds % 60 ) * 1000 + milli_seconds ) * sign
657+ if sign < 0 :
658+ time_int = (1 << bits ) + time_int
659+ formatstring = '{:0%ib}' % bits
660+ byte_hex = hex (int (formatstring .format (time_int ), 2 )).split ('x' )[1 ]
661+ bytes_array = bytes .fromhex (byte_hex )
662+ bytearray_ [byte_index :byte_index + 4 ] = bytes_array
663+ return bytearray_
664+
665+
589666def set_usint (bytearray_ : bytearray , byte_index : int , _int : int ) -> bytearray :
590- """set unsigned small int
667+ """Set unsigned small int
591668
592669 Notes:
593670 Datatype `usint` (Unsigned small int) consists on 1 byte in the PLC.
@@ -749,7 +826,8 @@ class DB:
749826
750827 def __init__ (self , db_number : int , bytearray_ : bytearray ,
751828 specification : str , row_size : int , size : int , id_field : Optional [str ] = None ,
752- db_offset : Optional [int ] = 0 , layout_offset : Optional [int ] = 0 , row_offset : Optional [int ] = 0 , area : Optional [Areas ] = Areas .DB ):
829+ db_offset : Optional [int ] = 0 , layout_offset : Optional [int ] = 0 , row_offset : Optional [int ] = 0 ,
830+ area : Optional [Areas ] = Areas .DB ):
753831 """ Creates a new instance of the `Row` class.
754832
755833 Args:
@@ -844,14 +922,14 @@ class DB_Row:
844922 _specification : OrderedDict = OrderedDict () # row specification
845923
846924 def __init__ (
847- self ,
848- bytearray_ : bytearray ,
849- _specification : str ,
850- row_size : Optional [int ] = 0 ,
851- db_offset : int = 0 ,
852- layout_offset : int = 0 ,
853- row_offset : Optional [int ] = 0 ,
854- area : Optional [Areas ] = Areas .DB
925+ self ,
926+ bytearray_ : bytearray ,
927+ _specification : str ,
928+ row_size : Optional [int ] = 0 ,
929+ db_offset : int = 0 ,
930+ layout_offset : int = 0 ,
931+ row_offset : Optional [int ] = 0 ,
932+ area : Optional [Areas ] = Areas .DB
855933 ):
856934 """Creates a new instance of the `DB_Row` class.
857935
@@ -1012,7 +1090,7 @@ def get_value(self, byte_index: Union[str, int], type_: str) -> Union[ValueError
10121090 # add these three not implemented data typ to avoid
10131091 # 'Unable to get repr for class<snap7.util.DB_ROW>' error
10141092 elif type_ == 'TIME' :
1015- return 'read TIME not implemented'
1093+ return get_time ( bytearray_ , byte_index )
10161094
10171095 elif type_ == 'DATE' :
10181096 return 'read DATE not implemented'
@@ -1081,6 +1159,9 @@ def set_value(self, byte_index: Union[str, int], type: str, value: Union[bool, s
10811159 if type == 'SINT' and isinstance (value , int ):
10821160 return set_sint (bytearray_ , byte_index , value )
10831161
1162+ if type == 'TIME' and isinstance (value , str ):
1163+ return set_time (bytearray_ , byte_index , value )
1164+
10841165 raise ValueError
10851166
10861167 def write (self , client : Client ) -> None :
0 commit comments