Beemon Sensors
The Sensor
Class:
- class sensor.Sensor(recording_start_time_queue: Queue, config: Config | None = None)[source]
- __init__(recording_start_time_queue: Queue, config: Config | None = None)[source]
Initializer for all
Sensor
objects. Concrete subclasses are expected to call the parent classes’ initializer.- Parameters:
recording_start_time_queue (Queue) – A reference/pointer to the
multiprocessing.Queue
instance that houses thedatetime.datetime
’s at which recording is to begin for the sensor.config (Optional[Config]) – A reference/pointer to an existing beemon
Config
object, should one exist. IfNone
is provided, a new beemon configurationConfig
object will be created for thebeemon-config.ini
in the repository’s root directory.local_output_directory (Optional[str]) – The root directory to which files containing data recorded by the sensor should be output. If
None
is provided, this value will be determined by theConfig
object provided during instantiation. If noConfig
object was provided during instantiation, this value will default to the value specified in thebeemon-config.ini
found in the repository’s root directory.capture_duration_seconds (Optional[int]) – How long the sensor is to record for (in seconds) at the start of each pre-determined recording time in the
recording_start_time_queue
. IfNone
is provided, this value will be determined by theConfig
object provided during instantiation. If noConfig
object was provided during instantiation, this value will default to the value specified in thebeemon-config.ini
found in the repository’s root directory.capture_window_start_time (Optional[datetime]) – When the first recording (of
capture_duration_seconds
in length) should transpire. Thisdatetime.datetime
is inclusive, if a value of0800
is specified, the first recording will be taken at8:00 AM EDT
. IfNone
is provided, this value will be determined by theConfig
object provided during instantiation. If noConfig
object was provided during instantiation, this value will default to the value specified in thebeemon-config.ini
found in the repository’s root directory.capture_window_end_time (Optional[datetime]) – When the last recording (of
capture_duration_seconds
in length) should transpire. Thisdatetime.datetime
is inclusive, if a value of2000
is specified, the last recording will be taken at8:00 PM EDT
. IfNone
is provided, this value will be determined by theConfig
object provided during instantiation. If noConfig
object was provided during instantiation, this value will default to the value specified in thebeemon-config.ini
found in the repository’s root directory.
- classmethod __subclasshook__(subclass: type)[source]
Called when the built-in method
issubclass()
is called on theSensor
class. This method inspects vital class properties ofSensor
to ensure that the providedsubclass
is substitutable for the baseSensor
class. More formally, it is this method’s responsibility to enforce the Liskov Substitution Principal (LSP).- Parameters:
subclass (type) – The potential subclass of
sensor.Sensor
whose membership is to be conclusively determined.- Returns:
True if the provided
subclass
is an LSP-valid subclass ofsensor.Sensor
, False otherwise.- Return type:
- abstract record(filename: str, uploader_output_dir: str) Dict[str, Any] [source]
Concrete
Sensor
subclasses are required to implement this method. It is called every time that a pre-specified recording start time is read from theSensor.recording_start_time_queue
. In the overridden version of this method, concrete subclasses are expected to do the following:Instruct their constituent firmware/hardware to record for a duration of
Sensor.capture_duration_seconds
Call the
Sensor.update_health_status()
method with the result of the recording attempt.Save the intermittent results of that recording to a temporary file (in
/tmp
). This is only necessary for sensor recordings that are not instantaneous such as video and audio. Other sensors can record directly touploader_output_dir
as in step 4 below.Rename the recorded file (when finished) to the provided
filename
parameter.Move the final renamed file to the specified
uploader_output_dir
parameter (e.g./home/bee/appmais/bee_tmp/
). This will trigger the Uploader watching this directory to transfer the recording via SFTP to the remote server.Return a dictionary of
key:value
paired attributes which the concreteSensor
subclass wishes to send northbound to the AppMAIS server.
Notes
Concrete subclasses are welcome to use this method to reload the beemon configuration file (if changes made prior to the recording session should take effect without
"stopping"
and"starting"
the sensor again). This is a safe place to do so, as this method is guaranteed to be called whenever a scheduled recording start time (from theSensor.recording_start_time_queue
) arrives. However, note that any access to the config file may need to be made multiprocessing safe, as multiple concrete subclass object/processes could be reading from the same object concurrently.- Parameters:
filename (str) – What the file name of the recorded measurement should be. For instance:
"rpi4-11@2021-11-27@19-30-00"
. Note that it is up to the concrete subclass to designate and append the file type (e.g.".wav"
,".h264"
) to the providedfilename
.uploader_output_dir (str) – The local output directory which the
uploader.Uploader
multiprocessing.Process
is watching for file changes. The final (and renamed) recorded file should be output to this directory. For example:"home/bee/bee_tmp/video/2021-11-27/"
.
- Returns:
Dict[str, Any] A dictionary of key-value pairs corresponding to the recorded measurement from the sensor. For instance, the temperature sensor may return
{"Temperature": 45.5, "Humidity": 23.0}
whereas the scale sensor may return{"Weight": 20.00}
, and the audio sensor may return an empty dictionary. Whatever is returned by this method will be passed toSensor.transmit()
as kwargs. You must return a dictionary from this method, although you do not have to overrideSensor.transmit()
. IfSensor.transmit()
is not overridden, the dictionary you return from this method will be un-utilized. IfSensor.transmit()
is overridden, the dictionary returned from this method will be passed askwargs
to theSensor.transmit()
method to facilitate the sending of data northbound to ThingsBoard.
- run() None [source]
Houses the main-loop/process to manage recording for all beemon Sensor-like objects. This method runs repeatedly until the sensor’s
recording_start_time_queue
is empty. This queue is purged by theorchestrator.Orchestrator
class when a"stop <sensor>"
command is received. When this occurs, this method will return, allowing the garbage collector to terminate themultiprocessing.Process
instance gracefully.Todo
Modify exit condition to be a stop() command received in addition to an empty queue.
Notes
This method is invoked automatically on
multiprocessing.Process
instances when themultiprocessing.Process.start()
method is run. Theorchestrator.Orchestrator
instance will call thesensor.Sensor.start()
method directly, which then invokes this method.
- abstract start() None [source]
This method is called by the
orchestrator.Orchestrator
class (specifically in theorchestrator.Orchestrator.start_command()
method) when a"start <sensor>"
command is sent to theserver.Server
process. The parentSensor
class allows concrete subclasses to optionally override this method in order to perform potentially long-running hardware/firmware sensor initialization routines. Concrete subclasses are expected to call the parent classes’ method first.Notes
The abstract version of this method is intended to contain operations common to all concrete subclass
Sensor
objects during initialization. Currently, there are no common initialization operations besides logging.
- transmit(**kwargs) None [source]
Transmits the latest sensor measurement (from the concrete subclass) to the ThingsBoard/Dashboard server (at the location specified in the
beemon-config.ini
) in JSON format over MQTT.- Parameters:
**kwargs (Dict[str, Any]) – A dictionary of keyword arguments returned by the concrete subclass in
Sensor.record()
. Can be any number of key:value pairs.- Returns:
An optional error message which will be logged as a logger.error() by the parent Sensor class when this method is invoked.
- Return type:
Optional[str]
The Audio
Class:
- class sensor.Audio(recording_start_time_queue: Queue, config: Config | None = None, audio_sample_frequency_hz: int | None = 48000, sample_format: int | None = 24, channel_count: int | None = 1, gain: int | None = 49)[source]
- __init__(recording_start_time_queue: Queue, config: Config | None = None, audio_sample_frequency_hz: int | None = 48000, sample_format: int | None = 24, channel_count: int | None = 1, gain: int | None = 49)[source]
Initializer for objects of type
Audio
.Notes
This class is dynamically initialized (as with all concrete
Sensor
subclasses) in theorchestrator.Orchestrator._dynamically_initialize_sensors()
method.- Parameters:
recording_start_time_queue (
Queue
) – A reference/pointer to theQueue
instance that houses thedatetime
’s at which recording is to begin for the sensor.config (Optional[Config]) – A reference/pointer to an existing beemon
Config
object, should one exist. IfNone
is provided, a new beemon configurationConfig
object will be created for thebeemon-config.ini
in the repository’s root directory.audio_sample_frequency_hz (Optional[int]) –
Todo
Docstring.
If
None
is provided, this value will be determined by theConfig
object provided during instantiation. If noConfig
object was provided during instantiation, this value will default to the value specified in thebeemon-config.ini
found in the repository’s root directory.sample_format (Optional[int]) –
Todo
Docstring.
If
None
is provided, this value will be determined by theConfig
object provided during instantiation. If noConfig
object was provided during instantiation, this value will default to the value specified in thebeemon-config.ini
found in the repository’s root directory.channel_count (Optional[int]) – The number of channels utilized by the microphone during recording. If the microphone is stereo (2-channel) then this class will attempt to convert to a mono signal (1-channel) via the
make_stereo_file_mono()
method.gain (Optional[int]) –
Todo
Docstring.
If
None
is provided, this value will be determined by theConfig
object provided during instantiation. If noConfig
object was provided during instantiation, this value will default to the value specified in thebeemon-config.ini
found in the repository’s root directory.
- static make_stereo_file_mono(out_path: str)[source]
If the mic must record a stereo file with redundant channels, this method will create a new file from just the left channel, and then overwrite the original file with the mono file before uploading it to the server.
- record(filename: str, uploader_output_dir: str) Dict[str, int] [source]
Instructs
ecasound
to record in a sub-process forself.capture_duration_seconds
to a temporary file in /tmp. Then this method moves the temporary file to the upload directory (via subprocess) when the recording subprocess has finished.- Parameters:
filename (str) – What the file name of the recorded measurement should be. For instance:
"rpi4-11@2021-11-27@19-30-00"
.uploader_output_dir (str) – The local output directory which the
uploader.Uploader
multiprocessing.Process
is watching for file changes. The final (and renamed) recorded file should be output to this directory. For example:"home/bee/bee_tmp/video/2021-11-27/"
.
- Returns:
Dictionary to upload to thingsboard, {‘Audio’: 0} if there are no errors and {‘Audio’: -1} if there is an error.
- Return type:
The Video
Class:
- class sensor.Video(recording_start_time_queue: Queue, config: Config | None = None, fps: int | None = 30, resolution_x: int | None = 640, resolution_y: int | None = 480, flip_video: bool | None = False, still_frame: bool | None = False)[source]
- __init__(recording_start_time_queue: Queue, config: Config | None = None, fps: int | None = 30, resolution_x: int | None = 640, resolution_y: int | None = 480, flip_video: bool | None = False, still_frame: bool | None = False)[source]
- Parameters:
recording_start_time_queue (Queue) – A reference/pointer to the
Queue
instance that houses thedatetime
’s at which recording is to begin for the sensor.config (Optional[Config]) – A reference/pointer to an existing beemon
Config
object, should one exist. IfNone
is provided, a new beemon configurationConfig
object will be created for thebeemon-config.ini
in the repository’s root directory.fps (Optional[int]) –
Todo
Docstring.
If
None
is provided, this value will be determined by theConfig
object provided during instantiation. If noConfig
object was provided during instantiation, this value will default to the value specified in thebeemon-config.ini
found in the repository’s root directory.resolution_x (Optional[int]) –
Todo
Docstring.
If
None
is provided, this value will be determined by theConfig
object provided during instantiation. If noConfig
object was provided during instantiation, this value will default to the value specified in thebeemon-config.ini
found in the repository’s root directory.resolution_y (Optional[int]) –
Todo
Docstring.
If
None
is provided, this value will be determined by theConfig
object provided during instantiation. If noConfig
object was provided during instantiation, this value will default to the value specified in thebeemon-config.ini
found in the repository’s root directory.flip_video (Optional[int]) –
Todo
Docstring.
If
None
is provided, this value will be determined by theConfig
object provided during instantiation. If noConfig
object was provided during instantiation, this value will default to the value specified in thebeemon-config.ini
found in the repository’s root directory.still_frame (Optional[bool]) – Whether or not to take images instead of a video. If
True
, then a single frame is captured instead of a video. Theframes_per_second
setting is ignored when capturing a still frame and theflip_video
setting will flip both videos and still frame recordings. IfFalse
a video will be captured instead. IfNone
is provided, this value will be determined by theConfig
object provided during instantiation. If noConfig
object was provided during instantiation, this value will default to the value specified in thebeemon-config.ini
found in the repository’s root directory.
- record(filename: str, uploader_output_dir: str) Dict[str, Any] [source]
- Presumably opens a filestream-like buffer (via the
picamera2.Picamera2
context manager) and records a video performing an IO-blocking operation for the duration set with
self.capture_duration_seconds
.The video initially records to a tmp file in the
/tmp
directory. The file is then moved to uploader_output_dir when the recoding is complete.- If
still_frame
in the beemon-config.ini is set toTrue
, then a single frame is captured instead of a video. The
frames_per_second
setting is ignored when capturing a still frame and theflip_video
setting will flip both videos and still frame recordings.
- Parameters:
filename (str) – What the file name of the recorded measurement should be. For instance:
"rpi4-11@2021-11-27@19-30-00"
.uploader_output_dir (str) – The local output directory which the
uploader.Uploader
multiprocessing.Process
is watching for file changes. The final (and renamed) recorded file should be output to this directory. For example:"home/bee/bee_tmp/video/2021-11-27/"
.
- Presumably opens a filestream-like buffer (via the
The Temp
Class:
- class sensor.Temp(recording_start_time_queue: Queue, config: Config | None = None)[source]
- __init__(recording_start_time_queue: Queue, config: Config | None = None)[source]
- Parameters:
recording_start_time_queue (Queue) – A reference/pointer to the
multiprocessing.Queue
instance that houses thedatetime.datetime
’s at which recording is to begin for the sensor.config (Optional[Config]) – A reference/pointer to an existing beemon
Config
object, should one exist. IfNone
is provided, a new beemon configurationConfig
object will be created for thebeemon-config.ini
in the repository’s root directory.
- record(filename: str, uploader_output_dir: str) Dict[str, float] [source]
Utilizes the
Adafruit_DHT
library to take a temperature and humidity reading from the sensor, appending it to a new CSV file daily. This method then copies the daily record of temperature and humidity readings into the upload directory, and copies an additional version to the sensor aggregation directory.This sensor writes directly to the
uploader_output_dir
; it does NOT write to the/tmp
directory. It writes to the csv file via thesrc.utils.filehandlingutils.write_sensor_csv_file()
method. Logic for determining the final sensor recording of the day (via a .final file extension) is found there.
- start() None [source]
This method is called by the
orchestrator.Orchestrator
class (specifically in theorchestrator.Orchestrator.start_command()
method) when a"start <sensor>"
command is sent to theserver.Server
process. The parentSensor
class allows concrete subclasses to optionally override this method in order to perform potentially long-running hardware/firmware sensor initialization routines. Concrete subclasses are expected to call the parent classes’ method first.Notes
The abstract version of this method is intended to contain operations common to all concrete subclass
Sensor
objects during initialization. Currently, there are no common initialization operations besides logging.
The AirQuality
Class:
- class sensor.AirQuality(recording_start_time_queue: Queue, config: Config | None = None)[source]
- __init__(recording_start_time_queue: Queue, config: Config | None = None)[source]
- Parameters:
recording_start_time_queue (Queue) – A reference/pointer to the
multiprocessing.Queue
instance that houses thedatetime.datetime
’s at which recording is to begin for the sensor.config (Optional[Config]) – A reference/pointer to an existing beemon
Config
object, should one exist. IfNone
is provided, a new beemon configurationConfig
object will be created for thebeemon-config.ini
in the repository’s root directory.
- _get_device_path() str [source]
Dynamically obtains the device path of the air quality sensor and returns it. Ex. “/dev/tty/USB0” on success and None on failure.
- Returns:
The device path on success, and the empty string on failure
- record(filename: str, uploader_output_dir: str) Dict[str, float] [source]
Utilizes the
sds011
library to take a air quality reading from the sensor, appending it to a new CSV file daily. This method then copies the daily record of air quality readings into the upload directory, and copies an additional version to the sensor aggregation directory.This sensor writes directly to the
uploader_output_dir
; it does NOT write to the/tmp
directory. It writes to the csv file via thesrc.utils.filehandlingutils.write_sensor_csv_file()
method. Logic for determining the final sensor recording of the day (via a .final file extension) is found there.See also
The SDS011 sensor’s datasheet. The definitions of pm25 and pm10.
- start() None [source]
This method is called by the
orchestrator.Orchestrator
class (specifically in theorchestrator.Orchestrator.start_command()
method) when a"start <sensor>"
command is sent to theserver.Server
process. The parentSensor
class allows concrete subclasses to optionally override this method in order to perform potentially long-running hardware/firmware sensor initialization routines. Concrete subclasses are expected to call the parent classes’ method first.Notes
The abstract version of this method is intended to contain operations common to all concrete subclass
Sensor
objects during initialization. Currently, there are no common initialization operations besides logging.
The Scale
Class:
- class sensor.Scale(recording_start_time_queue: Queue, config: Config | None = None)[source]
- __init__(recording_start_time_queue: Queue, config: Config | None = None)[source]
- Parameters:
recording_start_time_queue (Queue) – A reference/pointer to the
multiprocessing.Queue
instance that houses thedatetime.datetime
’s at which recording is to begin for the sensor.config (Optional[Config]) – A reference/pointer to an existing beemon
Config
object, should one exist. IfNone
is provided, a new beemon configurationConfig
object will be created for thebeemon-config.ini
in the repository’s root directory.
- record(filename: str, uploader_output_dir: str) Dict[str, Any] [source]
Utilizes the
hx711_multi
library to take a weight reading from the scale, appending it to a new CSV file daily. This method then copies the daily record of weight readings into the upload directory, and copies an additional version to the sensor aggregation directory.This sensor writes directly to the
uploader_output_dir
; it does NOT write to the/tmp
directory. It writes to the csv file via thesrc.utils.filehandlingutils.write_sensor_csv_file()
method. Logic for determining the final sensor recording of the day (via a .final file extension) is found there.- Returns:
A dictionary that contains a “Scale” reading (str) and the weight measured (float) in kilograms (kg). A weight reading of 50kg would be returned as {“Scale”: 50}
- Return type:
Dict[str, Any]
- start() None [source]
This method is called by the
orchestrator.Orchestrator
class (specifically in theorchestrator.Orchestrator.start_command()
method) when a"start <sensor>"
command is sent to theserver.Server
process. The parentSensor
class allows concrete subclasses to optionally override this method in order to perform potentially long-running hardware/firmware sensor initialization routines. Concrete subclasses are expected to call the parent classes’ method first.Notes
The abstract version of this method is intended to contain operations common to all concrete subclass
Sensor
objects during initialization. Currently, there are no common initialization operations besides logging.
The Cpu
Class:
- class sensor.Cpu(recording_start_time_queue: Queue, config: Config | None = None)[source]
- __init__(recording_start_time_queue: Queue, config: Config | None = None)[source]
- Parameters:
recording_start_time_queue (Queue) – A reference/pointer to the
multiprocessing.Queue
instance that houses thedatetime.datetime
’s at which recording is to begin for the sensor.config (Optional[Config]) – A reference/pointer to an existing beemon
Config
object, should one exist. IfNone
is provided, a new beemon configurationConfig
object will be created for thebeemon-config.ini
in the repository’s root directory.
- record(filename: str, uploader_output_dir: str) Dict[str, float] [source]
This sensor writes directly to the
uploader_output_dir
; it does NOT write to the/tmp
directory. It writes to the csv file via thesrc.utils.filehandlingutils.write_sensor_csv_file()
method. Logic for determining the final sensor recording of the day (via a .final file extension) is found there.
- start() None [source]
This method is called by the
orchestrator.Orchestrator
class (specifically in theorchestrator.Orchestrator.start_command()
method) when a"start <sensor>"
command is sent to theserver.Server
process. The parentSensor
class allows concrete subclasses to optionally override this method in order to perform potentially long-running hardware/firmware sensor initialization routines. Concrete subclasses are expected to call the parent classes’ method first.Notes
The abstract version of this method is intended to contain operations common to all concrete subclass
Sensor
objects during initialization. Currently, there are no common initialization operations besides logging.