Commit 81c10085 authored by Olivier R-D's avatar Olivier R-D

use python datetime instead of DateTime, fix tests

parent 8d501b27
......@@ -10,7 +10,7 @@ if __name__ == "__main__":
logging.basicConfig(level=logging.WARN)
logger = logging.getLogger("opcua.address_space")
#logger = logging.getLogger("opcua.internal_server")
logger.setLevel(logging.DEBUG)
#logger.setLevel(logging.DEBUG)
server = Server()
server.set_endpoint("opc.tcp://localhost:4841/freeopcua/server/")
server.set_server_name("FreeOpcUa Example Server")
......
"""
Internal server to be used on server side
"""
from datetime import datetime
import uuid
import logging
from threading import RLock
from threading import RLock, Timer
from opcua import ua
from opcua import utils
from opcua import Node
from opcua.address_space import AddressSpace
from opcua.standard_address_space_part3 import create_standard_address_space_Part3
from opcua.standard_address_space_part4 import create_standard_address_space_Part4
......@@ -48,6 +50,25 @@ class InternalServer(object):
create_standard_address_space_Part13(self.aspace)
self.channels = {}
self._lock = RLock()
#set some node values expected by some clients
self.current_time_node = Node(self, ua.NodeId(ua.ObjectIds.Server_ServerStatus_CurrentTime))
self._stopev = False
def start(self):
Node(self, ua.NodeId(ua.ObjectIds.Server_ServerStatus_State)).set_value(0)
Node(self, ua.NodeId(ua.ObjectIds.Server_ServerStatus_StartTime)).set_value(datetime.now())
# set time every seconds, maybe we should disable it for performance reason??
self._set_current_time()
def stop(self):
self._stopev = True
def _set_current_time(self):
if self._stopev:
return
self.current_time_node.set_value(datetime.now())
self._timer = Timer(1, self._set_current_time)
self._timer.start()
def open_secure_channel(self, params, currentchannel=None):
self.logger.info("open secure channel")
......@@ -61,7 +82,7 @@ class InternalServer(object):
else:
channel = self.channels[currentchannel.SecurityToken.ChannelId]
channel.SecurityToken.TokenId += 1
channel.SecurityToken.CreatedAt = ua.DateTime()
channel.SecurityToken.CreatedAt = datetime.now()
channel.SecurityToken.RevisedLifetime = params.RequestedLifetime
channel.ServerNonce = uuid.uuid4().bytes + uuid.uuid4().bytes
self.channels[channel.SecurityToken.ChannelId] = channel
......
......@@ -57,11 +57,13 @@ class Server(object):
self.name = name
def start(self):
self.iserver.start()
self._set_endpoints()
self.bserver = BinaryServer(self.iserver, self.endpoint.hostname, self.endpoint.port)
self.bserver.start()
def stop(self):
self.iserver.stop()
self.bserver.stop()
......
This diff is collapsed.
......@@ -8,8 +8,15 @@ import struct
import opcua.status_code as status_code
#UaTypes = ("Boolean", "SByte", "Byte", "Int16", "UInt16", "Int32", "UInt32", "Int64", "UInt64", "Float", "Double", "String", "DateTime", "Guid", "ByteString")
UaTypes = ("Boolean", "SByte", "Byte", "Int8", "UInt8", "Int16", "UInt16", "Int32", "UInt32", "Int64", "UInt64", "Float", "Double") #, "String", "DateTime", "Guid", "ByteString")
#types that will packed and unpacked directly using struct (string, bytes and datetime are handles as special cases
UaTypes = ("Boolean", "SByte", "Byte", "Int8", "UInt8", "Int16", "UInt16", "Int32", "UInt32", "Int64", "UInt64", "Float", "Double")
def datetime_to_win_epoch(dt):
epch = (dt - datetime(1601, 1, 1, 0, 0)).total_seconds() * 10 ** 7
return int(epch)
def win_epoch_to_datetime(epch):
return datetime(1601, 1, 1) + timedelta(microseconds=epch/10.0)
def uatype_to_fmt(uatype):
#if uatype == "String":
......@@ -65,6 +72,9 @@ def pack_uatype(uatype, value):
return pack_string(value)
elif uatype in ("CharArray", "ByteString"):
return pack_bytes(value)
elif uatype == "DateTime":
epch = datetime_to_win_epoch(value)
return struct.pack('<q', epch)
elif uatype in UaTypes:
fmt = '<' + uatype_to_fmt(uatype)
return struct.pack(fmt, value)
......@@ -76,6 +86,9 @@ def unpack_uatype(uatype, data):
return unpack_string(data)
elif uatype in ("CharArray", "ByteString"):
return unpack_bytes(data)
elif uatype == "DateTime":
epch = struct.unpack('<q', data.read(8))[0]
return win_epoch_to_datetime(epch)
elif uatype in UaTypes:
fmt = '<' + uatype_to_fmt(uatype)
size = struct.calcsize(fmt)
......@@ -398,21 +411,15 @@ class QualifiedName(object):
return 'QualifiedName({}:{})'.format(self.NamespaceIndex, self.Name)
__repr__ = __str__
'''
class DateTime(object):
def __init__(self, data=None):
if data is None:
self.data = self._to1601(datetime.now())
self.data = datetime_to_win_epoch(datetime.now())
else:
self.data = data
def _to1601(self, dt):
return (dt - datetime(1601, 1, 1, 0, 0)).total_seconds() * 10 ** 7
def to_datetime(self):
us = self.data / 10.0
return datetime(1601, 1, 1) + timedelta(microseconds=us)
@staticmethod
def now():
return DateTime.from_datetime(datetime.now())
......@@ -420,7 +427,7 @@ class DateTime(object):
@staticmethod
def from_datetime(pydt):
dt = DateTime()
dt.data = dt._to1601(pydt)
dt.data = datetime_to_win_epoch(pydt)
return dt
def to_binary(self):
......@@ -439,12 +446,14 @@ class DateTime(object):
def to_time_t(self):
epoch = datetime.utcfromtimestamp(0)
delta = self.to_datetime() - epoch
delta = self.win_epoch_to_datetime(self.data)() - epoch
return delta.total_seconds()
def __str__(self):
return "Datetime({})".format(self.to_datetime().isoformat())
return "Datetime({})".format(win_epoch_to_datetime(self.data).isoformat())
__repr__ = __str__
'''
class VariantType(Enum):
'''
......@@ -490,12 +499,11 @@ class Variant(object):
self.VariantType = self._guess_type(self.Value)
else:
self.VariantType = varianttype
#special case for python datetime
if type(self.Value) is datetime:
self.Value = DateTime.from_datetime(self.Value)
#FIXME: finish
#if type(self.Value) in (list, tuple) :
#self.Value = [DateTime.from_datetime(i) for i in self.Value]
def __eq__(self, other):
if isinstance(other, Variant) and self.VariantType == other.VariantType and self.Value == other.Value:
return True
return False
def _guess_type(self, val):
if val is None:
......@@ -511,8 +519,7 @@ class Variant(object):
elif type(val) == datetime:
return VariantType.DateTime
else:
raise Exception("Could not guess variant type, specify type")
raise Exception("Could not guess UA type of {} with type {}, specify UA type".format(val, type(val)))
def __str__(self):
return "Variant(val:{},type:{})".format(self.Value, self.VariantType)
......@@ -552,14 +559,13 @@ class DataValue(object):
'''
def __init__(self, variant=None):
self.Encoding = 0
if variant is None:
self.Value = Variant()
else:
self.Value = variant
if not type(variant) is Variant:
variant = Variant(variant)
self.Value = variant
self.StatusCode = StatusCode()
self.SourceTimestamp = DateTime()
self.SourceTimestamp = datetime.now()#DateTime()
self.SourcePicoseconds = 0
self.ServerTimestamp = DateTime()
self.ServerTimestamp = datetime.now()#DateTime()
self.ServerPicoseconds = 0
def to_binary(self):
......@@ -576,9 +582,9 @@ class DataValue(object):
if self.StatusCode:
packet.append(self.StatusCode.to_binary())
if self.SourceTimestamp:
packet.append(self.SourceTimestamp.to_binary())
packet.append(pack_uatype('DateTime', self.SourceTimestamp))#self.SourceTimestamp.to_binary())
if self.ServerTimestamp:
packet.append(self.ServerTimestamp.to_binary())
packet.append(pack_uatype('DateTime', self.ServerTimestamp))#self.ServerTimestamp.to_binary())
if self.SourcePicoseconds:
packet.append(pack_uatype('UInt16', self.SourcePicoseconds))
if self.ServerPicoseconds:
......@@ -594,9 +600,9 @@ class DataValue(object):
if obj.Encoding & (1 << 1):
obj.StatusCode = StatusCode.from_binary(data)
if obj.Encoding & (1 << 2):
obj.SourceTimestamp = DateTime.from_binary(data)
obj.SourceTimestamp = unpack_uatype('DateTime', data)#DateTime.from_binary(data)
if obj.Encoding & (1 << 3):
obj.ServerTimestamp = DateTime.from_binary(data)
obj.ServerTimestamp = unpack_uatype('DateTime', data)#DateTime.from_binary(data)
if obj.Encoding & (1 << 4):
obj.SourcePicoseconds = unpack_uatype('UInt16', data)
if obj.Encoding & (1 << 5):
......
......@@ -77,7 +77,7 @@ class Field(object):
__repr__ = __str__
def is_native_type(self):
if self.uatype in ("Char", "SByte", "Int8", "Int16", "Int32", "Int64", "UInt8", "UInt16", "UInt32", "UInt64", "Boolean", "Double", "Float", "Byte", "String", "CharArray", "ByteString"):
if self.uatype in ("Char", "SByte", "Int8", "Int16", "Int32", "Int64", "UInt8", "UInt16", "UInt32", "UInt64", "Boolean", "Double", "Float", "Byte", "String", "CharArray", "ByteString", "DateTime"):
return True
return False
......
......@@ -40,6 +40,8 @@ class CodeGenerator(object):
self.write("Autogenerate code from xml spec")
self.write("'''")
self.write("")
self.write("from datetime import datetime")
self.write("")
self.write("from opcua.uatypes import *")
self.write("from opcua.object_ids import ObjectIds")
self.write("")
......@@ -215,6 +217,8 @@ class CodeGenerator(object):
return "b''"
elif field.uatype in ("Boolean"):
return "True"
elif field.uatype in ("DateTime"):
return "datetime.now()"
elif field.uatype in ("Int8", "Int16", "Int32", "Int64", "UInt8", "UInt16", "UInt32", "UInt64", "Double", "Float", "Byte"):
return 0
else:
......
#! /usr/bin/env python
import io
import sys
import datetime
from datetime import datetime
import unittest
from threading import Thread, Event
try:
......@@ -84,14 +84,6 @@ class Unit(unittest.TestCase):
d = obj.to_binary()
print(d)
def test_datetime(self):
dt = ua.DateTime()
print(dt)
n = ua.DateTime.now()
print(n)
d = n.to_binary()
self.assertEqual(len(d), 8)
def test_qualified_name(self):
qn = ua.QualifiedName("Root", 0)
print(qn)
......@@ -147,35 +139,42 @@ class Unit(unittest.TestCase):
def test_datavalue(self):
dv = ua.DataValue(123)
self.assertEqual(dv.Value, 123)
self.assertEqual(dv.Value, ua.Variant(123))
self.assertEqual(type(dv.Value), ua.Variant)
dv = ua.DataValue('abc')
self.assertEqual(dv.Value, 'abc')
#tnow = int(time.time())
#dv.source_timestamp = ua.DateTime.from_time_t(tnow)
self.assertEqual(dv.Value, ua.Variant('abc'))
now = datetime.now()
dv.source_timestamp = now
#self.assertEqual(int(dv.source_timestamp.to_time_t()), tnow)
def test_variant(self):
dv = ua.Variant(True, ua.VariantType.Boolean)
self.assertEqual(dv.Value, True)
self.assertEqual(type(dv.Value), bool)
now = datetime.now()
v = ua.Variant(now)
self.assertEqual(v.Value, now)
self.assertEqual(v.VariantType, ua.VariantType.DateTime)
v2 = ua.Variant.from_binary(ua.utils.Buffer(v.to_binary()))
#self.assertEqual(v.Value, v2.Value)
self.assertEqual(v.VariantType, v2.VariantType)
def test_variant_array(self):
v = ua.Variant([1,2,3,4,5])
self.assertEqual(v.Value[1], 2)
#self.assertEqual(v.VarianType, ua.VariantType.Int64) # we do not care, we should aonly test for sutff that matter
v2 = ua.Variant.from_binary(ua.utils.Buffer(v.to_binary()))
self.assertEqual(v.Value, v2.Value)
self.assertEqual(v.VariantType, v2.VariantType)
now = datetime.now()
v = ua.Variant([now])
self.assertEqual(v.Value[0], now)
self.assertEqual(v.VariantType, ua.VariantType.DateTime)
v2 = ua.Variant.from_binary(ua.utils.Buffer(v.to_binary()))
#self.assertEqual(v.Value, v2.Value)
self.assertEqual(v.VariantType, v2.VariantType)
"""
def test_datetime(self):
tnow1 = int(time.time())
tnow = int((datetime.datetime.utcnow() - datetime.datetime(1970,1,1)).total_seconds())
self.assertEqual(tnow, tnow1) #if this one fails this is a system error, not freopcua
dt = ua.DateTime.from_time_t(tnow)
self.assertEqual(tnow, dt.to_time_t())
pydt = dt.to_datetime()
self.assertEqual(tnow, int((pydt - datetime.datetime(1970,1,1)).total_seconds()))
dt2 = ua.DateTime(pydt)
#self.assertEqual(dt2, dt) #FIXME: not implemented
pydt2 = dt.to_datetime()
self.assertEqual(pydt, pydt2)
"""
class CommonTests(object):
'''
......@@ -276,7 +275,7 @@ class CommonTests(object):
def test_datetime_write(self):
time_node = self.opc.get_node(ua.NodeId(ua.ObjectIds.Server_ServerStatus_CurrentTime))
now = datetime.datetime.now()
now = datetime.now()
objects = self.opc.get_objects_node()
v1 = objects.add_variable(4, "test_datetime", now)
tid = v1.get_value()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment