Merge commit '19709d9db73a71f291fbf5a417da328c16ea6e92' into Gwendal
This commit is contained in:
commit
c8f377aa80
24
README.md
24
README.md
|
@ -1,4 +1,4 @@
|
||||||
# puredata
|
# puredata class
|
||||||
|
|
||||||
This repo contains a short puredata class with some examples and a webserver.
|
This repo contains a short puredata class with some examples and a webserver.
|
||||||
Use pandoc to generate the index.html in the source directory.
|
Use pandoc to generate the index.html in the source directory.
|
||||||
|
@ -9,6 +9,28 @@ Dependencies:
|
||||||
* pandoc
|
* pandoc
|
||||||
* python3 bottle framework
|
* python3 bottle framework
|
||||||
|
|
||||||
|
It also includes a small OSC server that can be used to dispatch data to clients.
|
||||||
|
This server fetches JSON data from online sources and formats it to OSC bundles.
|
||||||
|
It currently dispatches:
|
||||||
|
|
||||||
|
* weather data
|
||||||
|
* bitcoin price data
|
||||||
|
* cpu and ram data
|
||||||
|
|
||||||
|
To run the server you need these python3 dependencies that can be installed with pip.
|
||||||
|
|
||||||
|
* python-osc
|
||||||
|
* psutil
|
||||||
|
|
||||||
|
The server **listens** on port **8080** and send OSC data back on port **8081** to the client who requested the data.
|
||||||
|
The following OSC messages can be sent to the server.
|
||||||
|
|
||||||
|
```python
|
||||||
|
/get/weather [CITY]
|
||||||
|
/get/bitcoin
|
||||||
|
/get/cpu
|
||||||
|
```
|
||||||
|
|
||||||
# todo
|
# todo
|
||||||
|
|
||||||
* restructure so that there is a intro section with video examples of nice patches
|
* restructure so that there is a intro section with video examples of nice patches
|
||||||
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
import psutil
|
||||||
|
import datetime
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
import requests
|
||||||
|
from pythonosc.osc_server import ThreadingOSCUDPServer
|
||||||
|
from pythonosc.dispatcher import Dispatcher
|
||||||
|
from pythonosc.osc_bundle_builder import OscBundleBuilder
|
||||||
|
from pythonosc.osc_bundle_builder import IMMEDIATELY
|
||||||
|
from pythonosc.osc_message_builder import OscMessageBuilder
|
||||||
|
from pythonosc.udp_client import SimpleUDPClient
|
||||||
|
|
||||||
|
logger = logging.getLogger("root")
|
||||||
|
|
||||||
|
class cpuData(object):
|
||||||
|
logger = logger.getChild("cpuData")
|
||||||
|
@classmethod
|
||||||
|
def get_data(cls):
|
||||||
|
cls.logger.info("getting data")
|
||||||
|
data = {}
|
||||||
|
data["cpu"] = psutil.cpu_freq().current
|
||||||
|
data["ram"] = psutil.virtual_memory().percent
|
||||||
|
data = cls._construct_osc_bundle(data)
|
||||||
|
return data
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _construct_osc_bundle(cls, data):
|
||||||
|
bundle = OscBundleBuilder(IMMEDIATELY)
|
||||||
|
for key, value in data.items():
|
||||||
|
msg = OscMessageBuilder("/cpu/{}".format(key))
|
||||||
|
msg.add_arg(value)
|
||||||
|
bundle.add_content(msg.build())
|
||||||
|
bundle = bundle.build()
|
||||||
|
return bundle
|
||||||
|
|
||||||
|
|
||||||
|
class openWeatherData(object):
|
||||||
|
logger = logger.getChild("openWeatherData")
|
||||||
|
API_KEY = "4398785f60059433ff91c603e887f7ac"
|
||||||
|
URL = "http://api.openweathermap.org/data/2.5/weather?"
|
||||||
|
_data = {}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _request_city_data(cls, city):
|
||||||
|
url = "{}appid={}&q={}".format(
|
||||||
|
cls.URL,
|
||||||
|
cls.API_KEY,
|
||||||
|
city,
|
||||||
|
)
|
||||||
|
data = requests.get(url).json()
|
||||||
|
cls.logger.info(data)
|
||||||
|
cls._data[city] = data
|
||||||
|
return data
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_data(cls, city):
|
||||||
|
cls.logger.info("getting data")
|
||||||
|
city = str(city).lower()
|
||||||
|
if city not in cls._data.keys():
|
||||||
|
cls.logger.info("requesting city: {}".format(city))
|
||||||
|
cls._request_city_data(city)
|
||||||
|
data = cls._construct_osc_bundle(city)
|
||||||
|
return data
|
||||||
|
else:
|
||||||
|
cls.logger.info("retrieving city from internal database: {}".format(city))
|
||||||
|
data = cls._construct_osc_bundle(city)
|
||||||
|
return data
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _construct_osc_bundle(cls, city):
|
||||||
|
bundle = OscBundleBuilder(IMMEDIATELY)
|
||||||
|
for key, value in cls._data[city].items():
|
||||||
|
if isinstance(value, int):
|
||||||
|
msg = OscMessageBuilder("/weather/{}".format(key))
|
||||||
|
msg.add_arg(value)
|
||||||
|
bundle.add_content(msg.build())
|
||||||
|
if isinstance(value, dict):
|
||||||
|
for subkey, subvalue in value.items():
|
||||||
|
msg = OscMessageBuilder("/weather/{}/{}".format(key, subkey))
|
||||||
|
msg.add_arg(subvalue)
|
||||||
|
bundle.add_content(msg.build())
|
||||||
|
bundle = bundle.build()
|
||||||
|
return bundle
|
||||||
|
|
||||||
|
class bitcoinData(object):
|
||||||
|
logger = logger.getChild("bitcoinData")
|
||||||
|
URL = "https://api.coinmarketcap.com/v1/ticker/bitcoin/"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_data(cls):
|
||||||
|
cls.logger.info("getting data")
|
||||||
|
data = requests.get(cls.URL).json()
|
||||||
|
data = cls._construct_osc_bundle(data)
|
||||||
|
return data
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _construct_osc_bundle(cls, data):
|
||||||
|
bundle = OscBundleBuilder(IMMEDIATELY)
|
||||||
|
for element in data:
|
||||||
|
for key, value in element.items():
|
||||||
|
msg = OscMessageBuilder("/bitcoin/{}".format(key))
|
||||||
|
msg.add_arg(value)
|
||||||
|
bundle.add_content(msg.build())
|
||||||
|
bundle = bundle.build()
|
||||||
|
return bundle
|
||||||
|
|
||||||
|
class oscDataServer(object):
|
||||||
|
def __init__(self, port=8080):
|
||||||
|
self.logger = logger.getChild(self.__class__.__name__)
|
||||||
|
self._dispatcher = Dispatcher()
|
||||||
|
self._dispatcher.map("/get/cpu", self.get_cpu, needs_reply_address=True)
|
||||||
|
self._dispatcher.map("/get/weather", self.get_city, needs_reply_address=True)
|
||||||
|
self._dispatcher.map("/get/bitcoin", self.get_bitcoin, needs_reply_address=True)
|
||||||
|
self._weather_data = openWeatherData()
|
||||||
|
self._bitcoin_data = bitcoinData()
|
||||||
|
self._cpu_data = cpuData()
|
||||||
|
self._server = ThreadingOSCUDPServer(("0.0.0.0", port), self._dispatcher)
|
||||||
|
|
||||||
|
def main(self):
|
||||||
|
self.logger.info("starting server")
|
||||||
|
self._server.serve_forever()
|
||||||
|
|
||||||
|
def get_cpu(self, *args, **kwargs):
|
||||||
|
data = self._cpu_data.get_data()
|
||||||
|
client = SimpleUDPClient(args[0][0], port=8081)
|
||||||
|
client.send(data)
|
||||||
|
self.logger.info("data sent to {}".format(args[0][0]))
|
||||||
|
|
||||||
|
def get_bitcoin(self, *args, **kwargs):
|
||||||
|
data = self._bitcoin_data.get_data()
|
||||||
|
client = SimpleUDPClient(args[0][0], port=8081)
|
||||||
|
client.send(data)
|
||||||
|
self.logger.info("data sent to {}".format(args[0][0]))
|
||||||
|
|
||||||
|
def get_city(self, *args, **kwargs):
|
||||||
|
data = self._weather_data.get_data(args[2])
|
||||||
|
client = SimpleUDPClient(args[0][0], port=8081)
|
||||||
|
client.send(data)
|
||||||
|
self.logger.info("data sent to {}".format(args[0][0]))
|
||||||
|
|
||||||
|
def main():
|
||||||
|
server = oscDataServer()
|
||||||
|
server.main()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
|
streamhandler = logging.StreamHandler()
|
||||||
|
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||||
|
streamhandler.setFormatter(formatter)
|
||||||
|
logger.addHandler(streamhandler)
|
||||||
|
|
||||||
|
logger.info("hello world")
|
||||||
|
|
||||||
|
main()
|
||||||
|
|
Loading…
Reference in New Issue