Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Maxime Buquet
slixmpp
Commits
a2423b84
Commit
a2423b84
authored
Feb 06, 2014
by
Lance Stout
Browse files
Get the IoT plugins to pass tests on Py3
parent
49acdac7
Changes
5
Hide whitespace changes
Inline
Side-by-side
sleekxmpp/plugins/xep_0323/device.py
View file @
a2423b84
...
...
@@ -12,51 +12,51 @@ import datetime
import
logging
class
Device
(
object
):
"""
Example implementation of a device readout object.
"""
Example implementation of a device readout object.
Is registered in the XEP_0323.register_node call
The device object may be any custom implementation to support
specific devices, but it must implement the functions:
has_field
request_fields
"""
def
__init__
(
self
,
nodeId
,
fields
=
{}):
self
.
nodeId
=
nodeId
self
.
fields
=
fields
# see fields described below
# {'type':'numeric',
# 'name':'myname',
# 'value': 42,
# 'unit':'Z'}];
self
.
timestamp_data
=
{}
self
.
momentary_data
=
{}
self
.
momentary_timestamp
=
""
logging
.
debug
(
"Device object started nodeId %s"
,
nodeId
)
def
has_field
(
self
,
field
):
"""
Returns true if the supplied field name exists in this device.
"""
def
__init__
(
self
,
nodeId
,
fields
=
{}):
self
.
nodeId
=
nodeId
self
.
fields
=
fields
# see fields described below
# {'type':'numeric',
# 'name':'myname',
# 'value': 42,
# 'unit':'Z'}];
self
.
timestamp_data
=
{}
self
.
momentary_data
=
{}
self
.
momentary_timestamp
=
""
logging
.
debug
(
"Device object started nodeId %s"
,
nodeId
)
def
has_field
(
self
,
field
):
"""
Returns true if the supplied field name exists in this device.
Arguments:
field -- The field name
"""
if
field
in
self
.
fields
.
keys
():
return
True
;
return
False
;
def
refresh
(
self
,
fields
):
"""
override method to do the refresh work
refresh values from hardware or other
"""
pass
def
request_fields
(
self
,
fields
,
flags
,
session
,
callback
):
"""
Starts a data readout. Verifies the requested fields,
refreshes the data (if needed) and calls the callback
with requested data.
field -- The field name
"""
if
field
in
self
.
fields
.
keys
():
return
True
;
return
False
;
def
refresh
(
self
,
fields
):
"""
override method to do the refresh work
refresh values from hardware or other
"""
pass
def
request_fields
(
self
,
fields
,
flags
,
session
,
callback
):
"""
Starts a data readout. Verifies the requested fields,
refreshes the data (if needed) and calls the callback
with requested data.
Arguments:
...
...
@@ -65,153 +65,153 @@ class Device(object):
Formatted as a dictionary like { "flag name": "flag value" ... }
session -- Session id, only used in the callback as identifier
callback -- Callback function to call when data is available.
The callback function must support the following arguments:
The callback function must support the following arguments:
session -- Session id, as supplied in the request_fields call
nodeId -- Identifier for this device
result -- The current result status of the readout. Valid values are:
session -- Session id, as supplied in the request_fields call
nodeId -- Identifier for this device
result -- The current result status of the readout. Valid values are:
"error" - Readout failed.
"fields" - Contains readout data.
"done" - Indicates that the readout is complete. May contain
readout data.
timestamp_block -- [optional] Only applies when result != "error"
timestamp_block -- [optional] Only applies when result != "error"
The readout data. Structured as a dictionary:
{
timestamp: timestamp for this datablock,
fields: list of field dictionary (one per readout field).
readout field dictionary format:
{
type: The field type (numeric, boolean, dateTime, timeSpan, string, enum)
name: The field name
value: The field value
unit: The unit of the field. Only applies to type numeric.
dataType: The datatype of the field. Only applies to type enum.
flags: [optional] data classifier flags for the field, e.g. momentary
{
timestamp: timestamp for this datablock,
fields: list of field dictionary (one per readout field).
readout field dictionary format:
{
type: The field type (numeric, boolean, dateTime, timeSpan, string, enum)
name: The field name
value: The field value
unit: The unit of the field. Only applies to type numeric.
dataType: The datatype of the field. Only applies to type enum.
flags: [optional] data classifier flags for the field, e.g. momentary
Formatted as a dictionary like { "flag name": "flag value" ... }
}
}
error_msg -- [optional] Only applies when result == "error".
}
}
error_msg -- [optional] Only applies when result == "error".
Error details when a request failed.
"""
logging
.
debug
(
"request_fields called looking for fields %s"
,
fields
)
if
len
(
fields
)
>
0
:
# Check availiability
for
f
in
fields
:
if
f
not
in
self
.
fields
.
keys
():
self
.
_send_reject
(
session
,
callback
)
return
False
;
else
:
# Request all fields
fields
=
self
.
fields
.
keys
();
# Refresh data from device
# ...
logging
.
debug
(
"about to refresh device fields %s"
,
fields
)
self
.
refresh
(
fields
)
if
"momentary"
in
flags
and
flags
[
'momentary'
]
==
"true"
or
\
"all"
in
flags
and
flags
[
'all'
]
==
"true"
:
ts_block
=
{};
timestamp
=
""
;
if
len
(
self
.
momentary_timestamp
)
>
0
:
timestamp
=
self
.
momentary_timestamp
;
else
:
timestamp
=
self
.
_get_timestamp
();
field_block
=
[];
for
f
in
self
.
momentary_data
:
if
f
in
fields
:
field_block
.
append
({
"name"
:
f
,
"type"
:
self
.
fields
[
f
][
"type"
],
"unit"
:
self
.
fields
[
f
][
"unit"
],
"dataType"
:
self
.
fields
[
f
][
"dataType"
],
"value"
:
self
.
momentary_data
[
f
][
"value"
],
"flags"
:
self
.
momentary_data
[
f
][
"flags"
]});
ts_block
[
"timestamp"
]
=
timestamp
;
ts_block
[
"fields"
]
=
field_block
;
callback
(
session
,
result
=
"done"
,
nodeId
=
self
.
nodeId
,
timestamp_block
=
ts_block
);
return
from_flag
=
self
.
_datetime_flag_parser
(
flags
,
'from'
)
to_flag
=
self
.
_datetime_flag_parser
(
flags
,
'to'
)
for
ts
in
sorted
(
self
.
timestamp_data
.
keys
()):
tsdt
=
datetime
.
datetime
.
strptime
(
ts
,
"%Y-%m-%dT%H:%M:%S"
)
if
not
from_flag
is
None
:
if
tsdt
<
from_flag
:
#print (str(tsdt) + " < " + str(from_flag))
continue
if
not
to_flag
is
None
:
if
tsdt
>
to_flag
:
#print (str(tsdt) + " > " + str(to_flag))
continue
ts_block
=
{};
field_block
=
[];
for
f
in
self
.
timestamp_data
[
ts
]:
if
f
in
fields
:
field_block
.
append
({
"name"
:
f
,
"type"
:
self
.
fields
[
f
][
"type"
],
"unit"
:
self
.
fields
[
f
][
"unit"
],
"dataType"
:
self
.
fields
[
f
][
"dataType"
],
"value"
:
self
.
timestamp_data
[
ts
][
f
][
"value"
],
"flags"
:
self
.
timestamp_data
[
ts
][
f
][
"flags"
]});
ts_block
[
"timestamp"
]
=
ts
;
ts_block
[
"fields"
]
=
field_block
;
callback
(
session
,
result
=
"fields"
,
nodeId
=
self
.
nodeId
,
timestamp_block
=
ts_block
);
callback
(
session
,
result
=
"done"
,
nodeId
=
self
.
nodeId
,
timestamp_block
=
None
);
def
_datetime_flag_parser
(
self
,
flags
,
flagname
):
if
not
flagname
in
flags
:
return
None
dt
=
None
try
:
dt
=
datetime
.
datetime
.
strptime
(
flags
[
flagname
],
"%Y-%m-%dT%H:%M:%S"
)
except
ValueError
:
# Badly formatted datetime, ignore it
pass
return
dt
def
_get_timestamp
(
self
):
"""
Generates a properly formatted timestamp of current time
"""
return
datetime
.
datetime
.
now
().
replace
(
microsecond
=
0
).
isoformat
()
def
_send_reject
(
self
,
session
,
callback
):
"""
Sends a reject to the caller
"""
logging
.
debug
(
"request_fields called looking for fields %s"
,
fields
)
if
len
(
fields
)
>
0
:
# Check availiability
for
f
in
fields
:
if
f
not
in
self
.
fields
.
keys
():
self
.
_send_reject
(
session
,
callback
)
return
False
;
else
:
# Request all fields
fields
=
self
.
fields
.
keys
();
# Refresh data from device
# ...
logging
.
debug
(
"about to refresh device fields %s"
,
fields
)
self
.
refresh
(
fields
)
if
"momentary"
in
flags
and
flags
[
'momentary'
]
==
"true"
or
\
"all"
in
flags
and
flags
[
'all'
]
==
"true"
:
ts_block
=
{};
timestamp
=
""
;
if
len
(
self
.
momentary_timestamp
)
>
0
:
timestamp
=
self
.
momentary_timestamp
;
else
:
timestamp
=
self
.
_get_timestamp
();
field_block
=
[];
for
f
in
self
.
momentary_data
:
if
f
in
fields
:
field_block
.
append
({
"name"
:
f
,
"type"
:
self
.
fields
[
f
][
"type"
],
"unit"
:
self
.
fields
[
f
][
"unit"
],
"dataType"
:
self
.
fields
[
f
][
"dataType"
],
"value"
:
self
.
momentary_data
[
f
][
"value"
],
"flags"
:
self
.
momentary_data
[
f
][
"flags"
]});
ts_block
[
"timestamp"
]
=
timestamp
;
ts_block
[
"fields"
]
=
field_block
;
callback
(
session
,
result
=
"done"
,
nodeId
=
self
.
nodeId
,
timestamp_block
=
ts_block
);
return
from_flag
=
self
.
_datetime_flag_parser
(
flags
,
'from'
)
to_flag
=
self
.
_datetime_flag_parser
(
flags
,
'to'
)
for
ts
in
sorted
(
self
.
timestamp_data
.
keys
()):
tsdt
=
datetime
.
datetime
.
strptime
(
ts
,
"%Y-%m-%dT%H:%M:%S"
)
if
not
from_flag
is
None
:
if
tsdt
<
from_flag
:
#print (str(tsdt) + " < " + str(from_flag))
continue
if
not
to_flag
is
None
:
if
tsdt
>
to_flag
:
#print (str(tsdt) + " > " + str(to_flag))
continue
ts_block
=
{};
field_block
=
[];
for
f
in
self
.
timestamp_data
[
ts
]:
if
f
in
fields
:
field_block
.
append
({
"name"
:
f
,
"type"
:
self
.
fields
[
f
][
"type"
],
"unit"
:
self
.
fields
[
f
][
"unit"
],
"dataType"
:
self
.
fields
[
f
][
"dataType"
],
"value"
:
self
.
timestamp_data
[
ts
][
f
][
"value"
],
"flags"
:
self
.
timestamp_data
[
ts
][
f
][
"flags"
]});
ts_block
[
"timestamp"
]
=
ts
;
ts_block
[
"fields"
]
=
field_block
;
callback
(
session
,
result
=
"fields"
,
nodeId
=
self
.
nodeId
,
timestamp_block
=
ts_block
);
callback
(
session
,
result
=
"done"
,
nodeId
=
self
.
nodeId
,
timestamp_block
=
None
);
def
_datetime_flag_parser
(
self
,
flags
,
flagname
):
if
not
flagname
in
flags
:
return
None
dt
=
None
try
:
dt
=
datetime
.
datetime
.
strptime
(
flags
[
flagname
],
"%Y-%m-%dT%H:%M:%S"
)
except
ValueError
:
# Badly formatted datetime, ignore it
pass
return
dt
def
_get_timestamp
(
self
):
"""
Generates a properly formatted timestamp of current time
"""
return
datetime
.
datetime
.
now
().
replace
(
microsecond
=
0
).
isoformat
()
def
_send_reject
(
self
,
session
,
callback
):
"""
Sends a reject to the caller
Arguments:
session -- Session id, see definition in request_fields function
callback -- Callback function, see definition in request_fields function
"""
callback
(
session
,
result
=
"error"
,
nodeId
=
self
.
nodeId
,
timestamp_block
=
None
,
error_msg
=
"Reject"
);
"""
callback
(
session
,
result
=
"error"
,
nodeId
=
self
.
nodeId
,
timestamp_block
=
None
,
error_msg
=
"Reject"
);
def
_add_field
(
self
,
name
,
typename
,
unit
=
None
,
dataType
=
None
):
"""
Adds a field to the device
def
_add_field
(
self
,
name
,
typename
,
unit
=
None
,
dataType
=
None
):
"""
Adds a field to the device
Arguments:
name -- Name of the field
typename -- Type of the field (numeric, boolean, dateTime, timeSpan, string, enum)
unit -- [optional] only applies to "numeric". Unit for the field.
dataType -- [optional] only applies to "enum". Datatype for the field.
"""
self
.
fields
[
name
]
=
{
"type"
:
typename
,
"unit"
:
unit
,
"dataType"
:
dataType
};
"""
self
.
fields
[
name
]
=
{
"type"
:
typename
,
"unit"
:
unit
,
"dataType"
:
dataType
};
def
_add_field_timestamp_data
(
self
,
name
,
timestamp
,
value
,
flags
=
None
):
"""
Adds timestamped data to a field
def
_add_field_timestamp_data
(
self
,
name
,
timestamp
,
value
,
flags
=
None
):
"""
Adds timestamped data to a field
Arguments:
name -- Name of the field
...
...
@@ -219,37 +219,37 @@ class Device(object):
value -- Field value at the timestamp
flags -- [optional] data classifier flags for the field, e.g. momentary
Formatted as a dictionary like { "flag name": "flag value" ... }
"""
if
not
name
in
self
.
fields
.
keys
():
return
False
;
if
not
timestamp
in
self
.
timestamp_data
:
self
.
timestamp_data
[
timestamp
]
=
{};
"""
if
not
name
in
self
.
fields
.
keys
():
return
False
;
if
not
timestamp
in
self
.
timestamp_data
:
self
.
timestamp_data
[
timestamp
]
=
{};
self
.
timestamp_data
[
timestamp
][
name
]
=
{
"value"
:
value
,
"flags"
:
flags
};
return
True
;
self
.
timestamp_data
[
timestamp
][
name
]
=
{
"value"
:
value
,
"flags"
:
flags
};
return
True
;
def
_add_field_momentary_data
(
self
,
name
,
value
,
flags
=
None
):
"""
Sets momentary data to a field
def
_add_field_momentary_data
(
self
,
name
,
value
,
flags
=
None
):
"""
Sets momentary data to a field
Arguments:
name -- Name of the field
value -- Field value at the timestamp
flags -- [optional] data classifier flags for the field, e.g. momentary
Formatted as a dictionary like { "flag name": "flag value" ... }
"""
if
not
self
.
fields
.
has_key
(
name
)
:
return
False
;
if
flags
is
None
:
flags
=
{};
flags
[
"momentary"
]
=
"true"
self
.
momentary_data
[
name
]
=
{
"value"
:
value
,
"flags"
:
flags
};
return
True
;
def
_set_momentary_timestamp
(
self
,
timestamp
):
"""
This function is only for unit testing to produce predictable results.
"""
self
.
momentary_timestamp
=
timestamp
;
"""
if
name
not
in
self
.
fields
:
return
False
;
if
flags
is
None
:
flags
=
{};
flags
[
"momentary"
]
=
"true"
self
.
momentary_data
[
name
]
=
{
"value"
:
value
,
"flags"
:
flags
};
return
True
;
def
_set_momentary_timestamp
(
self
,
timestamp
):
"""
This function is only for unit testing to produce predictable results.
"""
self
.
momentary_timestamp
=
timestamp
;
sleekxmpp/plugins/xep_0323/stanza/sensordata.py
View file @
a2423b84
...
...
@@ -124,10 +124,10 @@ class Request(ElementBase):
def
get_nodes
(
self
):
"""Return all nodes."""
nodes
=
set
()
nodes
=
[]
for
node
in
self
[
'substanzas'
]:
if
isinstance
(
node
,
RequestNode
):
nodes
.
a
d
d
(
node
)
nodes
.
a
ppen
d
(
node
)
return
nodes
def
set_nodes
(
self
,
nodes
):
...
...
@@ -190,10 +190,10 @@ class Request(ElementBase):
def
get_fields
(
self
):
"""Return all fields."""
fields
=
set
()
fields
=
[]
for
field
in
self
[
'substanzas'
]:
if
isinstance
(
field
,
RequestField
):
fields
.
a
d
d
(
field
)
fields
.
a
ppen
d
(
field
)
return
fields
def
set_fields
(
self
,
fields
):
...
...
@@ -351,10 +351,10 @@ class Fields(ElementBase):
def
get_nodes
(
self
):
"""Return all nodes."""
nodes
=
set
()
nodes
=
[]
for
node
in
self
[
'substanzas'
]:
if
isinstance
(
node
,
FieldsNode
):
nodes
.
a
d
d
(
node
)
nodes
.
a
ppen
d
(
node
)
return
nodes
def
set_nodes
(
self
,
nodes
):
...
...
@@ -450,10 +450,10 @@ class FieldsNode(ElementBase):
def
get_timestamps
(
self
):
"""Return all timestamps."""
#print(str(id(self)) + " get_timestamps: ")
timestamps
=
set
()
timestamps
=
[]
for
timestamp
in
self
[
'substanzas'
]:
if
isinstance
(
timestamp
,
Timestamp
):
timestamps
.
a
d
d
(
timestamp
)
timestamps
.
a
ppen
d
(
timestamp
)
return
timestamps
def
set_timestamps
(
self
,
timestamps
):
...
...
@@ -634,10 +634,10 @@ class Timestamp(ElementBase):
def
get_datas
(
self
):
""" Return all data elements. """
datas
=
set
()
datas
=
[]
for
data
in
self
[
'substanzas'
]:
if
isinstance
(
data
,
Field
):
datas
.
a
d
d
(
data
)
datas
.
a
ppen
d
(
data
)
return
datas
def
set_datas
(
self
,
datas
):
...
...
sleekxmpp/plugins/xep_0325/device.py
View file @
a2423b84
...
...
@@ -11,36 +11,36 @@
import
datetime
class
Device
(
object
):
"""
Example implementation of a device control object.
"""
Example implementation of a device control object.
The device object may by any custom implementation to support
specific devices, but it must implement the functions:
has_control_field
set_control_fields
"""
"""
def
__init__
(
self
,
nodeId
):
self
.
nodeId
=
nodeId
;
self
.
control_fields
=
{};
def
__init__
(
self
,
nodeId
):
self
.
nodeId
=
nodeId
;
self
.
control_fields
=
{};
def
has_control_field
(
self
,
field
,
typename
):
"""
Returns true if the supplied field name exists
and the type matches for control in this device.
def
has_control_field
(
self
,
field
,
typename
):
"""
Returns true if the supplied field name exists
and the type matches for control in this device.
Arguments:
field -- The field name
field -- The field name
typename -- The expected type
"""
if
field
in
self
.
control_fields
and
self
.
control_fields
[
field
][
"type"
]
==
typename
:
return
True
;
return
False
;
"""
if
field
in
self
.
control_fields
and
self
.
control_fields
[
field
][
"type"
]
==
typename
:
return
True
;
return
False
;
def
set_control_fields
(
self
,
fields
,
session
,
callback
):
"""
Starts a control setting procedure. Verifies the fields,
sets the data and (if needed) and calls the callback.
def
set_control_fields
(
self
,
fields
,
session
,
callback
):
"""
Starts a control setting procedure. Verifies the fields,
sets the data and (if needed) and calls the callback.
Arguments:
fields -- List of control fields in tuple format:
...
...
@@ -48,50 +48,50 @@ class Device(object):
session -- Session id, only used in the callback as identifier
callback -- Callback function to call when control set is complete.
The callback function must support the following arguments:
The callback function must support the following arguments:
session -- Session id, as supplied in the
request_fields call
nodeId -- Identifier for this device
result -- The current result status of the readout.
Valid values are:
session -- Session id, as supplied in the
request_fields call
nodeId -- Identifier for this device
result -- The current result status of the readout.
Valid values are:
"error" - Set fields failed.
"ok" - All fields were set.
error_field -- [optional] Only applies when result == "error"
The field name that failed
(usually means it is missing)
error_msg -- [optional] Only applies when result == "error".
Error details when a request failed.
"""
if
len
(
fields
)
>
0
:
# Check availiability
for
name
,
typename
,
value
in
fields
:
if
not
self
.
has_control_field
(
name
,
typename
):
self
.
_send_control_reject
(
session
,
name
,
"NotFound"
,
callback
)
return
False
;
for
name
,
typename
,
value
in
fields
:
self
.
_set_field_value
(
name
,
value
)
callback
(
session
,
result
=
"ok"
,
nodeId
=
self
.
nodeId
);
return
True
def
_send_control_reject
(
self
,
session
,
field
,
message
,
callback
):
"""
Sends a reject to the caller
error_field -- [optional] Only applies when result == "error"
The field name that failed
(usually means it is missing)
error_msg -- [optional] Only applies when result == "error".