A modular and threaded Python IoT framework to easily integrate sensors into your projects.
The goal of this project is to make it dead simple to add sensors to your projects. SimpleSensor is modular, you can pick and choose pieces to use from the contributed modules repo or build your own modules to custom needs. Feel free to contribute back modules, too.
In a basic use case a collection module can simply send messages along a communication module when a certain state or event is detected in a collection module. You can also orchestrate more complicated flows by communicating between modules before sending the message along communication channels.
For samples of how to integrate SimpleSensor with clients such as AEM Screens and vanilla Javascript, check out the samples branch of the contribution repository.
Modules are the building blocks of SimpleSensor. They typically have at least 4 parts:
- Main module class
- Config loader
- Zero or more config files
- An __init__.py, you must import the module class
as CollectionModule
(this is to simplify dynamic module imports)
The main module class extends the ModuleProcess base class, and runs on it's own thread or process. The logic of this class can be broken down into 3 stages:
- Initialize ➡️ perform any set up needed, either in
__init__()
or inrun()
before you begin the loop. - Loop ➡️ main logic of the module, repeats until a message is read to shutdown.
- Close ➡️ clean up anything that won't clean itself.
Used to collect data from a sensor, check if that data means something special has occurred, and send a Message if it has.
Example modules: bluetooth (BTLE) beacon, demographic camera
-
Initialize ➡️ initialize the sensor you'll be polling, set event condition, create variables and spawn threads if needed.
-
Loop ➡️ poll the sensor; if the condition is met, make a Message instance and put it on the queue with
put_message()
. -
Close ➡️ join threads you spawned, clean up the sensor, and mark the module as
alive=False
.
Used to send Messages
along a communication channel.
Examples modules: MQTT, websocket server, websocket client
-
Initialize ➡️ perform logic needed to operate the communication channel and the module, for example, handshakes or opening ports.
-
Loop ➡️ poll the
inQueue
for messages to send along the communication channel. -
Close ➡️ reverse whatever you did in initialize, then mark the module as
alive=False
.
The ThreadsafeLogger
is a simple facade to add messages to the logging queue, which is an instance of multiprocessing.Queue
that is shared among all modules. The logging queue is then consumed by the LoggingEngine
which passes those formatted messages to the Python logging module.
The default configuration logs to stderr
, as well as to a file located in the <run directory>/logs
directory.
To configure custom logging parameters, change the logging config file.
There are two ways to use SimpleSensor:
-
Configure base ➡️
/config/base.conf
-
Add modules ➡️ write, download, clone
-
Configure modules ➡️
<some module>/config/module.conf
and, if necessary,<some module>/config/secrets.conf
-
Run ➡️
python ./simplesensor/main.py
-
Install ➡️
pip install .
from the same directory assetup.py
-
Add/configure modules ➡️
scly install --type <communication or collection> --name <module branch name>
-
Configure base ➡️
scly config --name base
-
Run ➡️
scly start
More details on the CLI can be found in the CLI readme.
Source: simplesensor/shared/message.py
class simplesensor.shared.message.Message(topic, sender_id, sender_type, extended_data, recipients, timestamp)
Property | Required | Type | Description |
---|---|---|---|
topic |
Yes | String | Message type/topic |
sender_id |
Yes | String | ID property of original sender |
sender_type |
No | String | Type of sender, ie. collection point type, module name, hostname, etc |
extended_data |
No | Dictionary | Payload to deliver to recipient(s) |
recipients |
No | String or list[str] | Module name(s) to which the message will be delivered, ie. "websocket_server". - Use an array of strings to define multiple modules to send to. - Use "all" to send to all available modules. - Use "local_only" to send only to modules with low_cost prop set to True . - Use "communication_modules" to send only to communication modules. - Use "collection_modules" to send only to collection modules. |
timestamp |
No | ISO 8601 String | Timestamp of when the message was created |
Source: simplesensor/shared/moduleProcess.py
class simplesensor.shared.moduleProcess.ModuleProcess(baseConfig, pInBoundQueue, pOutBoundQueue, loggingQueue)
Base class for modules to inherit. Implements functions that are commonly used, defines the correct queue usage and parameter order.
This should not be instantiated itself, instead you should extend it with your own module and can initialize it in the __init__()
function with ModuleProcess.__init__(self, baseConfig, pInBoundQueue, pOutBoundQueue, loggingQueue)
.
For an example of how it can be used, see
Source: simplesensor/shared/threadsafeLogger.py
class simplesensor.shared.threadsafeLogger.ThreadsafeLogger(queue, name)
Docs go here
For contributing modules, please check out our module contribution repo
All submissions should come in the form of pull requests and will be reviewed by project contributors. Read GitHub's pull request documentation for more information on sending pull requests.
Issues should either include a proposal for a feature or, in the case of bugs, include the expected behavior, the actual behavior, your environment details, and ideally steps to reproduce. They should also ideally address actual issues with the code, not issues with setting up the environment. Please follow the issue template for consistency.
Pull requests should include references to the title of the issue, and changes proposed in the pull request. Please follow the pull request template for consistency.
This project adheres to the Adobe code of conduct. By participating, you are expected to uphold this code.