-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from jobe3774/Publish_Data_Thread
Publish data thread
- Loading branch information
Showing
11 changed files
with
442 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
#!/usr/bin/env python | ||
# -*- coding: utf-8 -*- | ||
# | ||
# raspend - Example | ||
# | ||
# License: MIT | ||
# | ||
# Copyright (c) 2019 Joerg Beckers | ||
|
||
import time | ||
import random | ||
import requests | ||
from requests.exceptions import HTTPError | ||
import argparse | ||
import getpass | ||
import json | ||
|
||
from raspend.application import RaspendApplication | ||
from raspend.utils import dataacquisition as DataAcquisition | ||
from raspend.utils import publishing as Publishing | ||
|
||
class DoorBell(): | ||
def __init__(self, *args, **kwargs): | ||
self.doorBellState = "on" | ||
|
||
def switchDoorBell(self, onoff): | ||
if type(onoff) == str: | ||
self.doorBellState = "on" if onoff == "on" else "off" | ||
elif type(onoff) == int: | ||
self.doorBellState = "on" if onoff >= 1 else "off" | ||
else: | ||
raise TypeError("State must be 'int' or 'string'.") | ||
return self.doorBellState | ||
|
||
def getCurrentState(self): | ||
return self.doorBellState | ||
|
||
class ReadOneWireTemperature(DataAcquisition.DataAcquisitionHandler): | ||
def __init__(self, groupId, sensorId, oneWireSensorPath = ""): | ||
# A groupId for grouping the temperature sensors | ||
self.groupId = groupId | ||
# The name or Id of your sensor under which you would read it's JSON value | ||
self.sensorId = sensorId | ||
# The path of your sensor within your system | ||
self.oneWireSensorPath = oneWireSensorPath | ||
|
||
def prepare(self): | ||
if self.groupId not in self.sharedDict: | ||
self.sharedDict[self.groupId] = {} | ||
self.sharedDict[self.groupId][self.sensorId] = 0 | ||
return | ||
|
||
def acquireData(self): | ||
# If you use 1-Wire sensors like a DS18B20 you normally would read its w1_slave file like: | ||
# /sys/bus/w1/devices/<the-sensor's system id>/w1_slave | ||
temp = random.randint(18, 24) | ||
self.sharedDict[self.groupId][self.sensorId] = temp | ||
return | ||
|
||
class PublishOneWireTemperatures(Publishing.PublishDataHandler): | ||
def __init__(self, endPointURL, userName, password): | ||
self.endPoint = endPointURL | ||
self.userName = userName | ||
self.password = password | ||
|
||
def prepare(self): | ||
# Nothing to prepare so far. | ||
pass | ||
|
||
def publishData(self): | ||
data = json.dumps(self.sharedDict) | ||
try: | ||
response = requests.post(self.endPoint, data, auth=(self.userName, self.password)) | ||
response.raise_for_status() | ||
except HTTPError as http_err: | ||
print("HTTP error occurred: {}".format(http_err)) | ||
except Exception as err: | ||
print("Unexpected error occurred: {}".format(err)) | ||
else: | ||
print(response.text) | ||
|
||
def main(): | ||
|
||
cmdLineParser = argparse.ArgumentParser(prog="example4", usage="%(prog)s [options]") | ||
cmdLineParser.add_argument("--port", help="The port the server should listen on", type=int, required=True) | ||
|
||
try: | ||
args = cmdLineParser.parse_args() | ||
except SystemExit: | ||
return | ||
|
||
username = input("Enter username: ") | ||
password = getpass.getpass("Enter password: ") | ||
|
||
myApp = RaspendApplication(args.port) | ||
|
||
theDoorBell = DoorBell() | ||
|
||
myApp.addCommand(theDoorBell.switchDoorBell) | ||
myApp.addCommand(theDoorBell.getCurrentState) | ||
|
||
myApp.updateSharedDict({"Starting Time" : time.asctime()}) | ||
|
||
myApp.createDataAcquisitionThread(ReadOneWireTemperature("basement", "party_room", "/sys/bus/w1/devices/23-000000000001/w1_slave"), 60) | ||
myApp.createDataAcquisitionThread(ReadOneWireTemperature("basement", "heating_room", "/sys/bus/w1/devices/23-000000000002/w1_slave"), 60) | ||
myApp.createDataAcquisitionThread(ReadOneWireTemperature("basement", "fitness_room", "/sys/bus/w1/devices/23-000000000003/w1_slave"), 60) | ||
myApp.createDataAcquisitionThread(ReadOneWireTemperature("ground_floor", "kitchen", "/sys/bus/w1/devices/23-000000000004/w1_slave"), 60) | ||
myApp.createDataAcquisitionThread(ReadOneWireTemperature("ground_floor", "living_room", "/sys/bus/w1/devices/23-000000000005/w1_slave"), 60) | ||
|
||
myApp.createPublishDataThread(PublishOneWireTemperatures("http://localhost/raspend_demo/api/post_data.php", username, password), 60) | ||
|
||
myApp.run() | ||
|
||
print ("Exit") | ||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
#!/usr/bin/env python | ||
# -*- coding: utf-8 -*- | ||
# | ||
# Simple classes that handle threaded data publishing. | ||
# | ||
# License: MIT | ||
# | ||
# Copyright (c) 2019 Joerg Beckers | ||
|
||
import threading | ||
import time | ||
|
||
class PublishDataHandler(): | ||
""" Base class for a handler which published data or parts of data store in the shared dictionary. | ||
Derive this class and override the 'publishData' - methods to publish the 'sharedDict'. | ||
""" | ||
|
||
def __init__(self, sharedDict=None): | ||
""" The contructor gets a dictionary containing any acquired data of your application. | ||
""" | ||
self.setSharedDict(sharedDict) | ||
|
||
def setSharedDict(self, sharedDict): | ||
""" Set the shared dictionary | ||
""" | ||
self.sharedDict = sharedDict | ||
|
||
def prepare(self): | ||
""" This method is called before the publish thread is started with this handler. | ||
So if you need to initialize parts of the shared dictionary you should override this method. | ||
""" | ||
pass | ||
|
||
def publishData(self): | ||
""" This method is called by a 'PublishDataThread'. Override this method publish your data in 'sharedDict'. | ||
""" | ||
pass | ||
|
||
class PublishDataThread(threading.Thread): | ||
""" A thread class which handles cyclic data publishing. | ||
An instance of this class needs a lock - object for controlling access to its 'publishDataHandler', an event - object for | ||
notifying the thread to exit and an object of a class derived from 'PublishDataHandler'. | ||
""" | ||
def __init__(self, threadSleep=0, shutdownFlag=None, dataLock=None, publishDataHandler=None): | ||
""" Contructs a new instance of 'PublishDataThread'. | ||
Parameters: | ||
threadSleep - milliseconds sleep time for the thread loop. | ||
shutdownFlag - a threading.event() object for notifying the thread to exit. | ||
dataLock - a threading.Lock() object for controlling access to the 'dataAcquisitionHandler'. | ||
publishDataHandler - an object of a class derived from 'PublishDataHandler'. | ||
""" | ||
threading.Thread.__init__(self) | ||
|
||
self.threadSleep = threadSleep | ||
self.shutdownFlag = shutdownFlag | ||
self.dataLock = dataLock | ||
self.publishDataHandler = publishDataHandler | ||
|
||
def run(self): | ||
""" The thread loop runs until 'shutdownFlag' has been signaled. Sleep for 'threadSleep' milliseconds. | ||
""" | ||
# Let the handler prepare itself if necessary. | ||
self.dataLock.acquire() | ||
self.publishDataHandler.prepare() | ||
self.dataLock.release() | ||
|
||
while not self.shutdownFlag.is_set(): | ||
# acquire lock | ||
self.dataLock.acquire() | ||
# call publish data handler | ||
self.publishDataHandler.publishData() | ||
# release lock | ||
self.dataLock.release() | ||
self.shutdownFlag.wait(self.threadSleep) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# Purpose | ||
|
||
**raspend_demo** is used for testing **raspend**'s publishing module. | ||
|
||
# Usage | ||
|
||
The easiest way to use **raspend_demo** is using Visual Studio Code with the PHP Debug extension installed (that's what I did). Then you need a web server with PHP enabled (I use [XAMPP](https://www.apachefriends.org/index.html)). To use the PHP Debug extension you further need to enable XDebug. See [PHP Debug extension](https://marketplace.visualstudio.com/items?itemName=felixfbecker.php-debug) for more information and follow the installations steps. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{ | ||
"version": "0.2.0", | ||
"configurations": [ | ||
{ | ||
"name": "Listen for XDebug", | ||
"type": "php", | ||
"request": "launch", | ||
"port": 9000 | ||
}, | ||
{ | ||
"name": "Launch currently open script", | ||
"type": "php", | ||
"request": "launch", | ||
"program": "${file}", | ||
"cwd": "${fileDirname}", | ||
"port": 9000 | ||
} | ||
] | ||
} |
Oops, something went wrong.