The wappstoiot module provide a simple python interface to wappsto.com for easy prototyping.
A wappsto.com Account, that the unit can connect to.
The wappsto module requires a set of certificates for authentication. The certificates can be downloaded from wappsto.com, or with the build-in CLI tool: python3 -m wappstoiot
.
The certificates provides the unit with the secure connection to wappsto.com.
To read more about how the Wappsto IoT inner workings, go here.
To understand how to use Wappsto IoT, there is some terms that need to be known.
- Control
- Change request value.
- Report
- The current value.
- Refresh
- Value Update request.
- Delete
- inform that a delete have happened.
- Network
- contains Devices
- Devices
- Contains Values
Wappsto IoT are using the python logging library for logging out the errors, warnings and debuging info. If comthing do not work as you expected, this will be a good place to start.
Wappsto IoT are also using docstring, so the build-in help function which will print a help page of the given function passed in.
For ease of use of the library, the names of device and values are used as a identifier, to link them to the ones found in you network on wappsto. Which means that you can not have two Devices of same name, or two value of same name under the same device.
The wappsto module can be installed using PIP (Python Package Index) as follows:
$ pip install -U wappstoiot
Working examples of usage can be found in the example folder.
The needed certificates can be downloaded with IoT Certificate Manager. Where path is the path to the config-folder, given in the following code example.
The following explains the example code found in echo.py.
wappstoiot.config(
config_folder="echo"
)
The config
function is setting up the folder for where Wappsto IoT are looking for the ca.crt
, client.key
and a client.crt
files, which is used to connect to Wappsto.
network = wappstoiot.createNetwork(
name="echo",
)
Set the displayed name of the network, and return the created network.
device = network.createDevice(
name="EchoDevice"
)
Set the displayed name of the device, under the given network that have been named: echo
.
value = device.createValue(
name="Moeller",
permission=wappstoiot.PermissionType.READWRITE,
value_template=wappstoiot.ValueTemplate.STRING
)
Set the displayed name of the value, under the given device that have been named: EchoDevice
.
It also set what the permission types of that value should be. Here it is set to both read & write. The naming is from the wappsto side. So read permission means that Wappsto can recreive a report from the device. A Write permission means that Wappsto can send a control value to the device.
Value template is set to be STRING, which inform wappsto, that the value will be of type string, with a max length of 64 charactor. The templates are used to avoid to setup the value yourself. If a custom String value are needed, look at method: createStringValue
insread.
value.onControl(
callback=lambda obj, new_value: obj.report(new_value)
)
Since the value permission include a write, is it needed to setup a control function, that are called when a control value are received. The function gets the value object in (obj), and the new target value (new_value) as parameters. The new value parameter neither a string or a float, since this is set as a STRING, the parameter will also be a string. In this example it just report back the value, which it can because it also have the read permission. The control function is then passed to the onControl method. Note that onControl can also be used as a function decorator. The control function should not be a blocking function.
value.onRefresh(
callback=lambda obj: obj.report(f"{obj.data} Refreshed!")
)
Since the value permission include a read, it is also possiable to request a update of the value. If this is behavier is wanted a refresh function need to be setup, which iscall when a refresh request is received. The function gets the value object in (obj). In this example it just report back the value with Refreshed!
append, which it can because it also have the read permission. The refresh function is then passed to the onRefresh method.
Note that onRefresh can also be used as a function decorator.
The refresh function should not be a blocking function.
try:
while True:
time.sleep(0.5)
except KeyboardInterrupt:
pass
finally:
wappstoiot.close()
With everything setup wappstoiot is non blocking. Which allowes the execution of other things.
Here there isn't there anything else to be executed, so that is setup a buzzy loop to prevent the program exiting.
When the user hits ctrl+c
, it stop the while-loop, and closes the wappsto connection.
config(
config_folder: Union[pathlib.Path, str] = '.',
connection: wappstoiot.ConnectionTypes = <ConnectionTypes.IOTAPI: 'jsonrpc'>,
fast_send: bool = True,
ping_pong_period_sec: Optional[int] = None,
offline_storage: Union[wappstoiot.utils.offline_storage.OfflineStorage, bool] = False,
rpc_timeout_sec: int = 3,
max_reconnect_retry_count: Optional[int] = None
) -> None
Configure the WappstoIoT settings.
This function call is optional. If it is not called, the default settings will be used for WappstoIoT. This function will also connect to the WappstoIoT API on call. In the cases that this function is not called, the connection will be make when an action is make that requests the connection.
Args: config_folder: The folder where it should find the certificate files. fast_send: whether or not it should wait for the sent message to be parsed. ping_pong_period_sec: The period for a ping package to be sent. offline_storage: If it should store value that failed in been sent. rpc_timeout_sec: The timeout for a sent RPC package. max_reconnect_retry_count: How many times it should try reconnect before throw an exception.
class ValueTemplate(builtins.str, enum.Enum):
All possible Value Permission Types.
- NONE
- READ
- WRITE
- READWRITE / WRITEREAD
class ValueTemplate(builtins.str, enum.Enum):
Predefined ValueTemplate. Each of the predefined ValueTemplate, have default value parameters set, which include BaseType, name, permission, range, step and the unit.
Avaliable Value Templates:
- ADDRESS_NAME
- ALTITUDE_M
- ANGLE
- APPARENT_POWER_VA
- BLOB
- BOOLEAN_ONOFF
- BOOLEAN_TRUEFALSE
- CITY
- CO2_PPM
- COLOR_HEX
- COLOR_INT
- COLOR_TEMPERATURE
- CONCENTRATION_PPM
- CONNECTION_STATUS
- COUNT
- COUNTRY
- COUNTRY_CODE
- CURRENT_A
- DISTANCE_M
- DURATION_MIN
- DURATION_MSEC
- DURATION_SEC
- ENERGY_KWH
- ENERGY_MWH
- ENERGY_PRICE_DKK_KWH
- ENERGY_PRICE_DKK_MWH
- ENERGY_PRICE_EUR_KWH
- ENERGY_PRICE_EUR_MWH
- ENERGY_WH
- FREQUENCY_HZ
- HUMIDITY
- IDENTIFIER
- IMAGE_JPG
- IMAGE_PNG
- IMPULSE_KWH
- INTEGER
- JSON
- LATITUDE
- LOAD_CURVE_ENERGY_KWH
- LOAD_CURVE_ENERGY_MWH
- LOAD_CURVE_ENERGY_WH
- LONGITUDE
- LUMINOSITY_LX
- NUMBER
- ORGANIZATION
- PERCENTAGE
- PHONE
- POSTCODE
- POWER_KW
- POWER_WATT
- PRECIPITATION_MM
- PRESSURE_HPA
- REACTIVE_ENERGY_KVARH
- REACTIVE_POWER_KVAR
- SPEED_KMH
- SPEED_MS
- STREET
- STRING
- TEMPERATURE_CELSIUS
- TEMPERATURE_FAHRENHEIT
- TEMPERATURE_KELVIN
- TIMESTAMP
- TIME_OF_DAY
- TOTAL_ENERGY_KWH
- TOTAL_ENERGY_MWH
- TOTAL_ENERGY_WH
- TRIGGER
- UNIT_TIME
- VOLTAGE_V
- VOLUME_M3
- XML
def onStatusChange(
StatusID: Union[service.StatusID, connection.StatusID],
callback: Callable[[Union[service.StatusID, connection.StatusID], Any], None]
) -> None:
Configure an action when the Status have changed.
class StatusID(builtins.str, enum.Enum):
The different states the service class can be in.
service Status IDs:
- ERROR
- IDLE
- SEND
- SENDERROR
- SENDING
class StatusID(builtins.str, enum.Enum):
The difference connection Statuses.
Connection Status IDs:
- CONNECTED
- CONNECTING
- DISCONNECTING
- DISCONNETCED
def createNetwork(
name: str,
description: str = "",
) -> Network:
Create a new Wappsto Network.
A Wappsto Network is references to the main grouping, of which multiple device are connected.
class Network(builtins.object):
name: str
uuid: uuid.UUID
def cancelOnChange(self) -> None:
Cancel the callback set in onChange-method.
def cancelOnCreate(self) -> None:
Cancel the callback set in onCreate-method.
def cancelOnDelete(self) -> None:
Cancel the callback set in onDelete-method.
def close(self) -> None:
Stop all the internal and children logic.
def delete(self) -> None:
Prompt a factory reset. Normally it is used to unclaim a Network & delete all children. This means that manufacturer and owner will be reset (or not), in relation of the rules set up in the certificates.
def onChange(
self,
callback: Callable[[ForwardRef('Network')], NoneType]
) -> Callable[[ForwardRef('Network')], NoneType]:
Configure a callback for when a change to the Network have occurred.
def onCreate(
self,
callback: Callable[[ForwardRef('Network')], NoneType]
) -> Callable[[ForwardRef('Network')], NoneType]:
Configure a callback for when a create have been make for the Device.
def onDelete(
self,
callback: Callable[[ForwardRef('Network')], NoneType]
) -> Callable[[ForwardRef('Network')], NoneType]
Configure an action when a Delete Network have been Requested.
Normally when a Delete have been requested on a Network, it is when it is not wanted anymore, and the Network have been unclaimed. Which mean that all the devices & value have to be recreated, and/or the program have to close.
def createDevice(
self,
name: str,
manufacturer: Optional[str] = None,
product: Optional[str] = None,
version: Optional[str] = None,
serial: Optional[str] = None,
protocol: Optional[str] = None,
communication: Optional[str] = None,
description: Optional[str] = None,
) -> wappstoiot.modules.device.Device:
Create a new Wappsto Device. A Wappsto Device is references something that is attached to the network that can be controlled or have values that can be reported to Wappsto. This could be a button that is connected to this unit, or in the case of this unit is a gateway, it could be a remote unit.
class Device:
name: str
uuid: uuid.UUID
def onDelete(
self,
callback: Callable[['Device'], None],
) -> Callable[['Device'], None]:
Configure an action when a Delete on this Device have been Requested.
Normally when a Delete have been requested, it is when it is not wanted anymore. Which mean that all the device and it's values have to be removed, and the process of setting up the device, should be executed again. This could result in the same device are created again, or if the device was not found, it will just be removed.
def cancelOnDelete(self) -> None:
Cancel the callback set in onDelete-method.
def onChange(
self,
callback: Callable[['Device'], None],
) -> Callable[['Device'], None]:
Configure a callback for when a change to the Device have occurred.
def cancelOnChange(self) -> None:
Cancel the callback set in onChange-method.
def onCreate(
self,
callback: Callable[['Device'], None],
) -> Callable[['Device'], None]:
Configure a callback for when a request have been make for the Value.
def cancelOnCreate(self) -> None:
Cancel the callback set in onCreate-method.
def delete(self) -> None:
Request a delete of the Device, & all it's Children.
def close(self) -> None:
Stop all the internal and children logic.
def createNumberValue(
self,
name: str,
*,
permission: PermissionType,
type: str,
min: Union[int, float],
max: Union[int, float],
step: Union[int, float],
unit: str,
description: Optional[str] = None,
si_conversion: Optional[str] = None,
period: Optional[int] = None, # in Sec
delta: Optional[Union[int, float]] = None,
mapping: Optional[Dict[str, str]] = None,
meaningful_zero: Optional[bool] = None,
ordered_mapping: Optional[bool] = None,
) -> Value:
Create a Wappsto Number Value.
A Wappsto Value is where the changing data can be found & are handled.
This require you to setup manually, what createValue
with value_template
setup for you.
Args: name: The displayed name on Wappsto. permission: Whether or not wappsto can read and/or write to the client. type: The displayed value on Wappsto. min: The displayed min on Wappsto. max: The displayed max on Wappsto. step: The displayed step on Wappsto. unit: The displayed unit on Wappsto. Ex: KW, m/s, hPa or m² description: The description of the value. si_conversion: Conversion algorithm from unit to a SI unit. Example for Wh to J: [J] = 3600 * [Wh] mapping: How the value should be displayed on Wappsto. Example: The mapping: {'0': 'false', '1': 'true'}, will on wappsto show 0 as false & 1 as true. But the value will still be 0 or 1. meaningful_zero: Whether or not a zero is truly nothing. ordered_mapping: Whether or not the order in the mapping matter. period: The time between forced update. the trigger is every multiplex from 00:00 o' clock. (Uses the callback set in onRefresh to force a update.) (Can be overwritten by Wappsto) delta: The change that need to happen before the value are updated and sent to wappsto. (Period & refresh request overwrites this) (Can be overwritten by Wappsto)
def createStringValue(
self,
name: str,
*,
permission: PermissionType,
type: str,
max: Union[int, float],
encoding: Optional[str] = None,
description: Optional[str] = None,
period: Optional[int] = None,
) -> Value:
Create a Wappsto String Value.
A Wappsto Value is where the changing data can be found & are handled.
This require you to setup manually, what createValue
with value_template
setup for you.
Args: name: The displayed name on Wappsto. permission: Whether or not wappsto can read and/or write to the client. type: The displayed string on Wappsto. max: The displayed max size on Wappsto. encoding: the encoding type of the data. Used to display the data correctly on wappsto. description: The description of the value. period: The time between forced update. the trigger is every multiplex from 00:00 o' clock. (Uses the callback set in onRefresh to force a update.) (Can be overwritten by Wappsto)
def createBlobValue(
self,
name: str,
*,
permission: PermissionType,
type: str,
max: Union[int, float],
encoding: Optional[str] = None,
description: Optional[str] = None,
period: Optional[int] = None,
) -> Value:
Create a Wappsto BLOB Value.
A Wappsto Value is where the changing data can be found & are handled.
This require you to setup manually, what createValue
with value_template
setup for you.
Args: name: The displayed name on Wappsto. permission: Whether or not wappsto can read and/or write to the client. type: The displayed string on Wappsto. max: The displayed max size on Wappsto. encoding: the encoding type of the data. Used to display the data correctly on wappsto. description: The description of the value. period: The time between forced update. the trigger is every multiplex from 00:00 o' clock. (Uses the callback set in onRefresh to force a update.) (Can be overwritten by Wappsto)
def createXmlValue(
self,
name: str,
*,
permission: PermissionType,
type: str,
xsd: Optional[str] = None,
namespace: Optional[str] = None,
description: Optional[str] = None,
period: Optional[int] = None,
) -> Value:
Create a Wappsto XML Value.
A Wappsto Value is where the changing data can be found & are handled.
This require you to setup manually, what createValue
with value_template
setup for you.
Args: name: The displayed name on Wappsto. permission: Whether or not wappsto can read and/or write to the client. type: The displayed string on Wappsto. xsd: The XMLs Schema definition. namespace: The XMLNamespace for the data. description: The description of the value. period: The time between forced update. the trigger is every multiplex from 00:00 o' clock. (Uses the callback set in onRefresh to force a update.) (Can be overwritten by Wappsto)
def createValue(
self,
name: str,
permission: PermissionType,
value_template: ValueTemplate,
description: Optional[str] = None,
period: Optional[int] = None,
delta: Optional[Union[int, float]] = None,
) -> Value:
Create a Wappsto Value.
A Wappsto Value is where the changing data can be found & are handled.
If a value_template have been set, that means that the parameters like: name, permission, min, max, step, encoding & unit have been set for you, to be the right settings for the given type. But you can still change it, if you choose sow.
It no ValueTemplate fits you need, take a look at: createNumberValue, createStringValue, createBlobValue or createXmlValue
Args: name: The displayed name on Wappsto. permission: Whether or not wappsto can read and/or write to the client. value_template: Contain pre-make config parameters. That is ensured to work well with Wappsto. Want something else? Use createNumberValue, createStringValue or createBlobValue. description: The description of the value. period: The time between forced update. the trigger is every multiplex from 00:00 o' clock. (Can be overwritten by Wappsto) (Uses the callback set in onRefresh to force a update.) delta: The change that need to happen before the value are updated and sent to wappsto. (Period & refresh request overwrites this) (Can be overwritten by Wappsto)
class Value:
name: str
uuid. uuid.UUID
def getControlData(self) -> Optional[Union[float, str]]:
Return the last Control value.
The returned value will be the last Control value, unless there isn't one, then it will return None.
def getControlTimestamp(self) -> Optional[datetime]:
Return the timestamp for when last Control value was updated.
The returned timestamp will be the last time Control value was updated, unless there isn't one, then it will return None.
def getReportData(self) -> Optional[Union[float, str]]:
Return the last Report value.
The returned value will be the last Report value. unless there isn't one, then it will return None.
def getReportTimestamp(self) -> Optional[datetime]:
Return the timestamp for when last Report value was updated.
The returned timestamp will be the last time Control value was updated, unless there isn't one, then it will return None.
def onChange(
self,
callback: Callable[['Value'], None],
) -> Callable[['Value'], None]:
Add a trigger on when change have been make.
A change on the Value typically will mean that a parameter, like period or delta or report value have been changed, from the server/user side.
Callback: ValueObj: The Object that have had a change to it. ChangeType: Name of what have change in the object.
def cancelOnChange(self) -> None:
Cancel the callback set in onChange-method.
def onReport(
self,
callback: Callable[['Value', Union[str, float]], None],
) -> Callable[['Value', Union[str, float]], None]:
Add a trigger on when Report data change have been make.
This trigger even if the Report data was changed to the same value.
Callback: Value: the Object that have had a Report for. Union[str, int, float]: The Value of the Report change.
def cancelOnReport(self) -> None:
Cancel the callback set in onReport-method.
def onControl(
self,
callback: Callable[['Value', Union[str, float]], None],
) -> Callable[['Value', Union[str, float]], None]:
Add trigger for when a Control request have been make.
A Control value is typical use to request a new target value, for the given value.
Callback: ValueObj: This object that have had a request for. any: The Data.
def cancelOnControl(self) -> None:
Cancel the callback set in onControl-method.
def onCreate(
self,
callback: Callable[['Value'], None],
) -> Callable[['Value'], None]:
Add trigger for when a state was created.
A Create is typical use to create a new state.
Callback: ValueObj: This object that have had a refresh request for.
def cancelOnCreate(self) -> None:
Cancel the callback set in onCreate-method.
def onRefresh(
self,
callback: Callable[['Value'], None],
) -> Callable[['Value'], None]:
Add trigger for when a Refresh where requested.
A Refresh is typical use to request a update of the report value, in case of the natural update cycle is not fast enough for the user, or a extra sample are wanted at that given time.
Callback: ValueObj: This object that have had a refresh request for.
def cancelOnRefresh(self) -> None:
Cancel the callback set in onRefresh-method.
def onDelete(
self,
callback: Callable[['Value'], None],
) -> Callable[['Value'], None]:
For when a 'DELETE' request have been called on this element.
def cancelOnDelete(self) -> None:
Cancel the callback set in onDelete-method.
def delete(self) -> None:
Request a delete of the Device, & all it's Children.
def report(
self,
value: Union[int, float, str, LogValue, List[LogValue], None],
timestamp: Optional[datetime] = None,
*,
force: bool = False,
add_jitter: bool = False,
) -> None:
Report the new current value to Wappsto.
The Report value is typical a measured value from a sensor, whether it is a GPIO pin, an analog temperature sensor or a device over a I2C bus.
def control(
self,
value: Union[int, float, str, None],
timestamp: Optional[datetime] = None
) -> None:
Report the a new control value to Wappsto.
A Control value is typical only changed if a target wanted value, have changed, whether it is because of an on device user controller, or the target was outside a given range.
def close(self) -> None:
Stop all the internal logic.
This project is licensed under the Apache License 2.0 - see the LICENSE.md file for details.