Mercurial > code > home > repos > homeauto
changeset 1732:3f4b447d65f5
port to starlette/asyncio
author | drewp@bigasterisk.com |
---|---|
date | Mon, 10 Jul 2023 17:37:58 -0700 |
parents | 35abc7656f0f |
children | 6279b1ac2b5e |
files | service/rdf_to_mqtt/Dockerfile service/rdf_to_mqtt/deploy.yaml service/rdf_to_mqtt/ingress.yaml service/rdf_to_mqtt/pdm.lock service/rdf_to_mqtt/pyproject.toml service/rdf_to_mqtt/rdf_over_http.py service/rdf_to_mqtt/rdf_to_mqtt.py service/rdf_to_mqtt/requirements.txt service/rdf_to_mqtt/serv.n3 service/rdf_to_mqtt/skaffold.yaml |
diffstat | 10 files changed, 481 insertions(+), 153 deletions(-) [+] |
line wrap: on
line diff
--- a/service/rdf_to_mqtt/Dockerfile Fri Jun 30 22:11:06 2023 -0700 +++ b/service/rdf_to_mqtt/Dockerfile Mon Jul 10 17:37:58 2023 -0700 @@ -1,14 +1,9 @@ -FROM bang5:5000/base_x86 +FROM bang5:5000/base_basic WORKDIR /opt -COPY requirements.txt ./ -RUN pip3 install --index-url https://projects.bigasterisk.com/ --extra-index-url https://pypi.org/simple -r requirements.txt -RUN pip3 install -U 'https://github.com/drewp/cyclone/archive/python3.zip?v3' -RUN pip3 install -U attrs +COPY pdm.lock pyproject.toml ./ +RUN pdm sync COPY *.py *.html *.js ./ -EXPOSE 10011:10011 - -CMD [ "python3", "./rdf_to_mqtt.py", "-v" ]
--- a/service/rdf_to_mqtt/deploy.yaml Fri Jun 30 22:11:06 2023 -0700 +++ b/service/rdf_to_mqtt/deploy.yaml Mon Jul 10 17:37:58 2023 -0700 @@ -15,17 +15,17 @@ containers: - name: rdf-to-mqtt image: bang5:5000/rdf_to_mqtt_image - imagePullPolicy: "Always" + args: + - pdm + - run + - uvicorn + - --access-log + - --host=0.0.0.0 + - --log-level=trace + - --port=8000 + - rdf_to_mqtt:app ports: - - containerPort: 10008 - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: "kubernetes.io/hostname" - operator: In - values: ["bang"] + - containerPort: 8000 --- apiVersion: v1 kind: Service @@ -33,6 +33,6 @@ name: rdf-to-mqtt spec: ports: - - {port: 10008, targetPort: 10008} + - { port: 80, targetPort: 8000 } selector: app: rdf-to-mqtt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/service/rdf_to_mqtt/ingress.yaml Mon Jul 10 17:37:58 2023 -0700 @@ -0,0 +1,27 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: rdf-to-mqtt + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + ingress.pomerium.io/allow_public_unauthenticated_access: "false" + ingress.pomerium.io/pass_identity_headers: "true" + ingress.pomerium.io/preserve_host_header: "true" + ingress.pomerium.io/policy: | + allow: + or: + - { email: { is: "drewpca@gmail.com" }} + - { email: { is: "kelsimp@gmail.com" }} + ingress.pomerium.io/prefix_rewrite: "/" +spec: + ingressClassName: pomerium + rules: + - host: "bigasterisk.com" + http: + paths: + - pathType: Prefix + path: /rdf_to_mqtt/ + backend: { service: { name: rdf-to-mqtt, port: { number: 80 } } } + tls: + - hosts: [bigasterisk.com] + secretName: bigasterisk.com-tls
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/service/rdf_to_mqtt/pdm.lock Mon Jul 10 17:37:58 2023 -0700 @@ -0,0 +1,297 @@ +# This file is @generated by PDM. +# It is not intended for manual editing. + +[[package]] +name = "aiomqtt" +version = "1.0.0" +requires_python = ">=3.7,<4.0" +summary = "The idiomatic asyncio MQTT client, wrapped around paho-mqtt" +dependencies = [ + "paho-mqtt<2.0.0,>=1.6.0", +] + +[[package]] +name = "anyio" +version = "3.7.1" +requires_python = ">=3.7" +summary = "High level compatibility layer for multiple asynchronous event loop implementations" +dependencies = [ + "exceptiongroup; python_version < \"3.11\"", + "idna>=2.8", + "sniffio>=1.1", +] + +[[package]] +name = "asyncio-mqtt" +version = "0.16.2" +requires_python = ">=3.7" +summary = "Idiomatic asyncio wrapper around paho-mqtt" +dependencies = [ + "paho-mqtt>=1.6.0", +] + +[[package]] +name = "certifi" +version = "2023.5.7" +requires_python = ">=3.6" +summary = "Python package for providing Mozilla's CA Bundle." + +[[package]] +name = "click" +version = "8.1.4" +requires_python = ">=3.7" +summary = "Composable command line interface toolkit" +dependencies = [ + "colorama; platform_system == \"Windows\"", +] + +[[package]] +name = "colorama" +version = "0.4.6" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +summary = "Cross-platform colored terminal text." + +[[package]] +name = "elasticsearch" +version = "7.17.9" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4" +summary = "Python client for Elasticsearch" +dependencies = [ + "certifi", + "urllib3<2,>=1.21.1", +] + +[[package]] +name = "elasticsearch-logging-handler" +version = "1.0.1" +requires_python = ">=3.7" +summary = "Minimalistic Elasticsearch logging handler" +dependencies = [ + "elasticsearch<8.0.0", + "pytz", +] + +[[package]] +name = "exceptiongroup" +version = "1.1.2" +requires_python = ">=3.7" +summary = "Backport of PEP 654 (exception groups)" + +[[package]] +name = "h11" +version = "0.14.0" +requires_python = ">=3.7" +summary = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" + +[[package]] +name = "idna" +version = "3.4" +requires_python = ">=3.5" +summary = "Internationalized Domain Names in Applications (IDNA)" + +[[package]] +name = "isodate" +version = "0.6.1" +summary = "An ISO 8601 date/time/duration parser and formatter" +dependencies = [ + "six", +] + +[[package]] +name = "logging-json" +version = "0.4.0" +requires_python = ">=3.7" +summary = "JSON formatter for python logging" + +[[package]] +name = "paho-mqtt" +version = "1.6.1" +summary = "MQTT version 5.0/3.1.1 client class" + +[[package]] +name = "prometheus-client" +version = "0.17.1" +requires_python = ">=3.6" +summary = "Python client for the Prometheus monitoring system." + +[[package]] +name = "pyparsing" +version = "3.1.0" +requires_python = ">=3.6.8" +summary = "pyparsing module - Classes and methods to define and execute parsing grammars" + +[[package]] +name = "pytz" +version = "2023.3" +summary = "World timezone definitions, modern and historical" + +[[package]] +name = "rdflib" +version = "6.3.2" +requires_python = ">=3.7,<4.0" +summary = "RDFLib is a Python library for working with RDF, a simple yet powerful language for representing information." +dependencies = [ + "isodate<0.7.0,>=0.6.0", + "pyparsing<4,>=2.1.0", +] + +[[package]] +name = "six" +version = "1.16.0" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +summary = "Python 2 and 3 compatibility utilities" + +[[package]] +name = "sniffio" +version = "1.3.0" +requires_python = ">=3.7" +summary = "Sniff out which async library your code is running under" + +[[package]] +name = "starlette" +version = "0.28.0" +requires_python = ">=3.7" +summary = "The little ASGI library that shines." +dependencies = [ + "anyio<5,>=3.4.0", +] + +[[package]] +name = "starlette-exporter" +version = "0.16.0" +summary = "Prometheus metrics exporter for Starlette applications." +dependencies = [ + "prometheus-client>=0.12", + "starlette", +] + +[[package]] +name = "urllib3" +version = "1.26.16" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +summary = "HTTP library with thread-safe connection pooling, file post, and more." + +[[package]] +name = "uvicorn" +version = "0.22.0" +requires_python = ">=3.7" +summary = "The lightning-fast ASGI server." +dependencies = [ + "click>=7.0", + "h11>=0.8", +] + +[[package]] +name = "victorialogger" +version = "0.4.0" +requires_python = ">=3.10" +summary = "" +dependencies = [ + "elasticsearch-logging-handler>=1.0.1", + "logging-json>=0.4.0", +] + +[metadata] +lock_version = "4.2" +cross_platform = true +groups = ["default"] +content_hash = "sha256:2e897ffd2914d6d86f5f5488ca6416c633b96eae1d855914f686b9b96d27137f" + +[metadata.files] +"aiomqtt 1.0.0" = [ + {url = "https://files.pythonhosted.org/packages/8c/d9/5e4859b847897d364cefb29e25d142d6031949499796e6808c24a36a1035/aiomqtt-1.0.0.tar.gz", hash = "sha256:a96c4af50f54ded0c07d4dfc14aa3e212265cbebf659e2ab64950cf14ba8dca2"}, + {url = "https://files.pythonhosted.org/packages/cf/7b/c842643452c12c02a1cbc03c9cef24188c81d7b557bd319ebd2c065dbf75/aiomqtt-1.0.0-py3-none-any.whl", hash = "sha256:dd6fe629c10ac24a3d2abc2bcc09afe4f66bc06b6457b63cf764cc81f3b980fe"}, +] +"anyio 3.7.1" = [ + {url = "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl", hash = "sha256:91dee416e570e92c64041bd18b900d1d6fa78dff7048769ce5ac5ddad004fbb5"}, + {url = "https://files.pythonhosted.org/packages/28/99/2dfd53fd55ce9838e6ff2d4dac20ce58263798bd1a0dbe18b3a9af3fcfce/anyio-3.7.1.tar.gz", hash = "sha256:44a3c9aba0f5defa43261a8b3efb97891f2bd7d804e0e1f56419befa1adfc780"}, +] +"asyncio-mqtt 0.16.2" = [ + {url = "https://files.pythonhosted.org/packages/2a/64/c8a8c2ed51f3c1f4b8d2f244424d3bad3fbd4333eb01589c6b00a6dd2c04/asyncio_mqtt-0.16.2-py3-none-any.whl", hash = "sha256:fe70ea2c648b248779a7ff3d9218262cdd739083743dfaa7c0d52ba458a8ad71"}, +] +"certifi 2023.5.7" = [ + {url = "https://files.pythonhosted.org/packages/93/71/752f7a4dd4c20d6b12341ed1732368546bc0ca9866139fe812f6009d9ac7/certifi-2023.5.7.tar.gz", hash = "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7"}, + {url = "https://files.pythonhosted.org/packages/9d/19/59961b522e6757f0c9097e4493fa906031b95b3ebe9360b2c3083561a6b4/certifi-2023.5.7-py3-none-any.whl", hash = "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"}, +] +"click 8.1.4" = [ + {url = "https://files.pythonhosted.org/packages/77/88/b0cc5fe95c31c301e9823ea9b028f669c0dcfa205ff71111037a5ed4892c/click-8.1.4.tar.gz", hash = "sha256:b97d0c74955da062a7d4ef92fadb583806a585b2ea81958a81bd72726cbb8e37"}, + {url = "https://files.pythonhosted.org/packages/f9/a6/dc327484918f1656cc9fcebebe77efcfc0ef0d447fa925a8760ee55abe0e/click-8.1.4-py3-none-any.whl", hash = "sha256:2739815aaa5d2c986a88f1e9230c55e17f0caad3d958a5e13ad0797c166db9e3"}, +] +"colorama 0.4.6" = [ + {url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] +"elasticsearch 7.17.9" = [ + {url = "https://files.pythonhosted.org/packages/19/3e/91d8970b17a898bbe01c1833e246cc231abddaf70ab987c3f2fd81142964/elasticsearch-7.17.9.tar.gz", hash = "sha256:66c4ece2adfe7cc120e2b6a6798a1fd5c777aecf82eec39bb95cef7cfc7ea2b3"}, + {url = "https://files.pythonhosted.org/packages/9b/0a/5ad75e5379bf01c044aa00e0ea893eab630cb5339db87b84436f2b762ffd/elasticsearch-7.17.9-py2.py3-none-any.whl", hash = "sha256:0e2454645dc00517dee4c6de3863411a9c5f1955d013c5fefa29123dadc92f98"}, +] +"elasticsearch-logging-handler 1.0.1" = [ + {url = "https://files.pythonhosted.org/packages/0f/62/acbf0fd217a44eaec7535ec2b0e5a94d7ed3266d6c07f39268afd1155f27/elasticsearch_logging_handler-1.0.1-py3-none-any.whl", hash = "sha256:b99c2ab7d64d756f7ef4d631d55e887b354ebd64d6577ba4b348cfba63666065"}, + {url = "https://files.pythonhosted.org/packages/9e/3a/c03e8df9ef1d6fa6ed2bd9cde95f4f350e9346414f8a949e43260a83493b/elasticsearch-logging-handler-1.0.1.tar.gz", hash = "sha256:9bb96f665b35aa46c33a7204adbcbd43a37895478ba11a8565c61d4bbe105a31"}, +] +"exceptiongroup 1.1.2" = [ + {url = "https://files.pythonhosted.org/packages/55/09/5d2079ecab0ca483e527a1707a483562bdc17abf829d3e73f0c1a73b61c7/exceptiongroup-1.1.2.tar.gz", hash = "sha256:12c3e887d6485d16943a309616de20ae5582633e0a2eda17f4e10fd61c1e8af5"}, + {url = "https://files.pythonhosted.org/packages/fe/17/f43b7c9ccf399d72038042ee72785c305f6c6fdc6231942f8ab99d995742/exceptiongroup-1.1.2-py3-none-any.whl", hash = "sha256:e346e69d186172ca7cf029c8c1d16235aa0e04035e5750b4b95039e65204328f"}, +] +"h11 0.14.0" = [ + {url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] +"idna 3.4" = [ + {url = "https://files.pythonhosted.org/packages/8b/e1/43beb3d38dba6cb420cefa297822eac205a277ab43e5ba5d5c46faf96438/idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, + {url = "https://files.pythonhosted.org/packages/fc/34/3030de6f1370931b9dbb4dad48f6ab1015ab1d32447850b9fc94e60097be/idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, +] +"isodate 0.6.1" = [ + {url = "https://files.pythonhosted.org/packages/b6/85/7882d311924cbcfc70b1890780763e36ff0b140c7e51c110fc59a532f087/isodate-0.6.1-py2.py3-none-any.whl", hash = "sha256:0751eece944162659049d35f4f549ed815792b38793f07cf73381c1c87cbed96"}, + {url = "https://files.pythonhosted.org/packages/db/7a/c0a56c7d56c7fa723988f122fa1f1ccf8c5c4ccc48efad0d214b49e5b1af/isodate-0.6.1.tar.gz", hash = "sha256:48c5881de7e8b0a0d648cb024c8062dc84e7b840ed81e864c7614fd3c127bde9"}, +] +"logging-json 0.4.0" = [ + {url = "https://files.pythonhosted.org/packages/1d/6d/42d547fd5c5e38a079d8d174da88864b1cfb8a0400c4464ee1af1d0451ac/logging_json-0.4.0.tar.gz", hash = "sha256:ab550d0a16c17a3de7740b1552738ff4f478093b1688902fa397d08ed1952678"}, + {url = "https://files.pythonhosted.org/packages/6f/a0/85b77c3b4daa9bc884d8c4f65e71cc11cb33b46da8d6b75ad8364cc5f793/logging_json-0.4.0-py3-none-any.whl", hash = "sha256:e56c0e79fd18573007ccef50fa98689f73c4640c5a2117e7375af0ac43ac95d7"}, +] +"paho-mqtt 1.6.1" = [ + {url = "https://files.pythonhosted.org/packages/f8/dd/4b75dcba025f8647bc9862ac17299e0d7d12d3beadbf026d8c8d74215c12/paho-mqtt-1.6.1.tar.gz", hash = "sha256:2a8291c81623aec00372b5a85558a372c747cbca8e9934dfe218638b8eefc26f"}, +] +"prometheus-client 0.17.1" = [ + {url = "https://files.pythonhosted.org/packages/ad/b3/6e18c89bf6bd120590ea538a62cae16dc763ff2745b18377c4be5495c4aa/prometheus_client-0.17.1-py3-none-any.whl", hash = "sha256:e537f37160f6807b8202a6fc4764cdd19bac5480ddd3e0d463c3002b34462101"}, + {url = "https://files.pythonhosted.org/packages/f5/05/aee33352594522c56eb4a4382b5acd9a706a030db9ba2fc3dc38a283e75c/prometheus_client-0.17.1.tar.gz", hash = "sha256:21e674f39831ae3f8acde238afd9a27a37d0d2fb5a28ea094f0ce25d2cbf2091"}, +] +"pyparsing 3.1.0" = [ + {url = "https://files.pythonhosted.org/packages/4f/13/28e88033cab976721512e7741000fb0635fa078045e530a91abb25aea0c0/pyparsing-3.1.0.tar.gz", hash = "sha256:edb662d6fe322d6e990b1594b5feaeadf806803359e3d4d42f11e295e588f0ea"}, + {url = "https://files.pythonhosted.org/packages/a4/24/6ae4c9c45cf99d96b06b5d99e25526c060303171fb0aea9da2bfd7dbde93/pyparsing-3.1.0-py3-none-any.whl", hash = "sha256:d554a96d1a7d3ddaf7183104485bc19fd80543ad6ac5bdb6426719d766fb06c1"}, +] +"pytz 2023.3" = [ + {url = "https://files.pythonhosted.org/packages/5e/32/12032aa8c673ee16707a9b6cdda2b09c0089131f35af55d443b6a9c69c1d/pytz-2023.3.tar.gz", hash = "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588"}, + {url = "https://files.pythonhosted.org/packages/7f/99/ad6bd37e748257dd70d6f85d916cafe79c0b0f5e2e95b11f7fbc82bf3110/pytz-2023.3-py2.py3-none-any.whl", hash = "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb"}, +] +"rdflib 6.3.2" = [ + {url = "https://files.pythonhosted.org/packages/af/92/d7fb1d7fb70c9f7003fa50b7a3880ebcb311cc3f8552b3595e7c8f75aeeb/rdflib-6.3.2-py3-none-any.whl", hash = "sha256:36b4e74a32aa1e4fa7b8719876fb192f19ecd45ff932ea5ebbd2e417a0247e63"}, + {url = "https://files.pythonhosted.org/packages/c8/28/4d1f27c5d73f58e567ca1a14a4eab7d7978a09c4e117687f9f6c216d3366/rdflib-6.3.2.tar.gz", hash = "sha256:72af591ff704f4caacea7ecc0c5a9056b8553e0489dd4f35a9bc52dbd41522e0"}, +] +"six 1.16.0" = [ + {url = "https://files.pythonhosted.org/packages/71/39/171f1c67cd00715f190ba0b100d606d440a28c93c7714febeca8b79af85e/six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, + {url = "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, +] +"sniffio 1.3.0" = [ + {url = "https://files.pythonhosted.org/packages/c3/a0/5dba8ed157b0136607c7f2151db695885606968d1fae123dc3391e0cfdbf/sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, + {url = "https://files.pythonhosted.org/packages/cd/50/d49c388cae4ec10e8109b1b833fd265511840706808576df3ada99ecb0ac/sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, +] +"starlette 0.28.0" = [ + {url = "https://files.pythonhosted.org/packages/ba/f3/3cca6acd03eb7e2da1dcf35148815d94e588bf7c1e555a002c888d8a23ee/starlette-0.28.0-py3-none-any.whl", hash = "sha256:e58b9fc402c579950260fbb6d57173395c4e62804c40d3ede7e9ef1074f0c579"}, + {url = "https://files.pythonhosted.org/packages/f2/7b/05e2ddc8d0da28c3c916d637cfe509d16e7a2e2cf7faa7cb888446326a30/starlette-0.28.0.tar.gz", hash = "sha256:7bf3da5e997e796cc202cef2bd3f96a7d9b1e1943203c2fe2b42e020bc658482"}, +] +"starlette-exporter 0.16.0" = [ + {url = "https://files.pythonhosted.org/packages/91/7a/1edb5c8de27ab3e28a4e6b1f96f5a9de1fffc2a645a095bc5368a0776dcb/starlette_exporter-0.16.0.tar.gz", hash = "sha256:728cccf975c85d3cf2844b0110b51e1fa2dce628ef68bc38da58ad691f9b5d68"}, + {url = "https://files.pythonhosted.org/packages/e6/bc/ca5f04ac95634ecba7199ca0912558bec91ca69449edbd2920915432f3c6/starlette_exporter-0.16.0-py3-none-any.whl", hash = "sha256:9dbe8dc647acbeb8680d53cedbbb8042ca75ca1b6987f609c5601ea96ddb7422"}, +] +"urllib3 1.26.16" = [ + {url = "https://files.pythonhosted.org/packages/c5/05/c214b32d21c0b465506f95c4f28ccbcba15022e000b043b72b3df7728471/urllib3-1.26.16-py2.py3-none-any.whl", hash = "sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f"}, + {url = "https://files.pythonhosted.org/packages/e2/7d/539e6f0cf9f0b95b71dd701a56dae89f768cd39fd8ce0096af3546aeb5a3/urllib3-1.26.16.tar.gz", hash = "sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14"}, +] +"uvicorn 0.22.0" = [ + {url = "https://files.pythonhosted.org/packages/ad/bd/d47ee02312640fcf26c7e1c807402d5c5eab468571153a94ec8f7ada0e46/uvicorn-0.22.0-py3-none-any.whl", hash = "sha256:e9434d3bbf05f310e762147f769c9f21235ee118ba2d2bf1155a7196448bd996"}, + {url = "https://files.pythonhosted.org/packages/c6/dd/0d3bab50ab4ef8bec849f89fec2adc2fabcc397018c30e57d9f0d4009c5e/uvicorn-0.22.0.tar.gz", hash = "sha256:79277ae03db57ce7d9aa0567830bbb51d7a612f54d6e1e3e92da3ef24c2c8ed8"}, +] +"victorialogger 0.4.0" = [ + {url = "https://projects.bigasterisk.com/victorialogger/victorialogger-0.4.0.tar.gz", hash = "sha256:9fae42f114b3808079b2c18764773d074077678720a52c598e2852e26eb0abac"}, +]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/service/rdf_to_mqtt/pyproject.toml Mon Jul 10 17:37:58 2023 -0700 @@ -0,0 +1,32 @@ +[project] +name = "" +version = "" +description = "" +authors = [{ name = "Drew Perttula", email = "drewp@bigasterisk.com" }] +dependencies = [ + "victorialogger>=0.4.0", + "starlette>=0.28.0", + "starlette-exporter>=0.16.0", + "uvicorn>=0.22.0", + "asyncio-mqtt>=0.16.2", + "aiomqtt>=1.0.0", + "rdflib>=6.3.2", +] +requires-python = ">=3.10" +license = { text = "MIT" } + +[build-system] +requires = ["pdm-pep517>=1.0.0"] +build-backend = "pdm.pep517.api" + +[tool] + +[tool.pdm] + +[tool.pdm.overrides] +pyopenssl = ">=22.0.0" + +[[tool.pdm.source]] +url = "https://projects.bigasterisk.com/" +verify_ssl = true +name = "home"
--- a/service/rdf_to_mqtt/rdf_over_http.py Fri Jun 30 22:11:06 2023 -0700 +++ b/service/rdf_to_mqtt/rdf_over_http.py Mon Jul 10 17:37:58 2023 -0700 @@ -19,9 +19,9 @@ def rdfStatementsFromRequest(arg, body, headers): if arg.get('s') and arg.get('p'): - subj = expandQueryParamUri(arg['s'][-1]) - pred = expandQueryParamUri(arg['p'][-1]) - turtleLiteral = body + subj = expandQueryParamUri(arg['s']) + pred = expandQueryParamUri(arg['p']) + turtleLiteral = body.decode('utf8') try: obj = Literal(float(turtleLiteral)) except ValueError:
--- a/service/rdf_to_mqtt/rdf_to_mqtt.py Fri Jun 30 22:11:06 2023 -0700 +++ b/service/rdf_to_mqtt/rdf_to_mqtt.py Mon Jul 10 17:37:58 2023 -0700 @@ -4,39 +4,49 @@ This is like light9/bin/collector. """ +import asyncio import json +import os +import time -import cyclone.web -from cycloneerr import PrettyErrorHandler -from docopt import docopt -from greplin import scales -from greplin.scales.cyclonehandler import StatsHandler -from mqtt_client import MqttClient +from prometheus_client import Counter, Gauge, Summary from rdflib import Namespace -from standardservice.logsetup import log, verboseLogging -from twisted.internet import reactor +from starlette_exporter import PrometheusMiddleware, handle_metrics +from starlette.applications import Starlette +from starlette.requests import Request +from starlette.responses import PlainTextResponse +from starlette.routing import Route +from starlette.staticfiles import StaticFiles +import aiomqtt + from devs import devs import rdf_over_http +# from victorialogger import log +import logging + +logging.basicConfig(level=logging.DEBUG) +log = logging.getLogger(__name__) + ROOM = Namespace('http://projects.bigasterisk.com/room/') -STATS = scales.collection( - '/root', - scales.PmfStat('putRequests'), - scales.PmfStat('statement'), - scales.PmfStat('mqttPublish'), -) +PUT_REQUESTS = Summary('put_requests', 'calls') +STATEMENT = Summary('on_statement', 'calls') +MQTT_PUBLISH = Summary('mqtt_publish', 'calls') + +mqtt: aiomqtt.Client | None = None -class OutputPage(PrettyErrorHandler, cyclone.web.RequestHandler): +class OutputPage: - @STATS.putRequests.time() - def put(self): - for stmt in rdf_over_http.rdfStatementsFromRequest(self.request.arguments, self.request.body, self.request.headers): - self._onStatement(stmt) + async def put(self, request: Request) -> PlainTextResponse: + with PUT_REQUESTS.time(): + for stmt in rdf_over_http.rdfStatementsFromRequest(request.query_params, await request.body(), request.headers): + await self._onStatement(stmt) + return PlainTextResponse("ok") - @STATS.statement.time() - def _onStatement(self, stmt): + @STATEMENT.time() + async def _onStatement(self, stmt): log.info(f'incoming statement: {stmt}') ignored = True for dev, attrs in devs.items(): @@ -47,100 +57,105 @@ brightness = stmt[2].toPython() if attrs.get('values', '') == 'binary': - self._publishOnOff(attrs, brightness) + await self._publishOnOff(attrs, brightness) else: - self._publishRgbw(attrs, brightness) + await self._publishRgbw(attrs, brightness) ignored = False if stmt[0:2] == (dev, ROOM['inputSelector']): - choice = stmt[2].toPython().decode('utf8') - self._publish(topic=attrs['root'], message=f'input_{choice}') + choice = stmt[2].toPython() + await self._publish(topic=attrs['root'], message=f'input_{choice}') ignored = False if stmt[0:2] == (dev, ROOM['volumeChange']): delta = int(stmt[2].toPython()) which = 'up' if delta > 0 else 'down' - self._publish(topic=f'theater_blaster/ir_out/volume_{which}', message=json.dumps({'timed': abs(delta)})) + await self._publish(topic=f'theater_blaster/ir_out/volume_{which}', message=json.dumps({'timed': abs(delta)})) ignored = False if stmt[0:2] == (dev, ROOM['color']): - h = stmt[2].toPython() - msg = {} - if h.endswith(b'K'): # accept "0.7*2200K" (brightness 0.7) - # see https://www.zigbee2mqtt.io/information/mqtt_topics_and_message_structure.html#zigbee2mqttfriendly_nameset - bright, kelvin = map(float, h[:-1].split(b'*')) - msg['state'] = 'ON' - msg["color_temp"] = round(1000000 / kelvin, 2) - msg['brightness'] = int(bright * 255) # 1..20 look about the same - else: - r, g, b = int(h[1:3], 16), int(h[3:5], 16), int(h[5:7], 16) - msg = { - 'state': 'ON' if r or g or b else 'OFF', - 'color': { - 'r': r, - 'g': g, - 'b': b - }, - 'brightness': max(r, g, b), - } - - if attrs.get('hasWhite', False): - msg['white_value'] = max(r, g, b) - msg.update(attrs.get('defaults', {})) - self._publish(topic=attrs['root'], message=json.dumps(msg)) + msg = self._onColor(stmt[2].toPython(), attrs) + await self._publish(topic=attrs['root'], message=json.dumps(msg)) ignored = False if ignored: log.warn("ignoring %s", stmt) - def _publishOnOff(self, attrs, brightness): + def _onColor(self, h, attrs): + if isinstance(h, bytes): + h = h.decode('utf8') + msg = {} + if h.endswith('K'): # accept "0.7*2200K" (brightness 0.7) + # see https://www.zigbee2mqtt.io/information/mqtt_topics_and_message_structure.html#zigbee2mqttfriendly_nameset + bright, kelvin = map(float, h[:-1].split('*')) + msg['state'] = 'ON' + msg["color_temp"] = round(1000000 / kelvin, 2) + msg['brightness'] = int(bright * 255) # 1..20 look about the same + else: + r, g, b = int(h[1:3], 16), int(h[3:5], 16), int(h[5:7], 16) + msg = { + 'state': 'ON' if r or g or b else 'OFF', + 'color': { + 'r': r, + 'g': g, + 'b': b + }, + 'brightness': max(r, g, b), + } + + if attrs.get('hasWhite', False): + msg['white_value'] = max(r, g, b) + msg.update(attrs.get('defaults', {})) + return msg + + async def _publishOnOff(self, attrs, brightness): msg = 'OFF' if brightness > 0: msg = 'ON' - self._publish(topic=attrs['root'], message=msg) + await self._publish(topic=attrs['root'], message=msg) - def _publishRgbw(self, attrs, brightness): + async def _publishRgbw(self, attrs, brightness): for chan, scale in [('w1', 1), ('r', 1), ('g', .8), ('b', .8)]: - self._publish(topic=f"{attrs['root']}/light/kit_{chan}/command", messageJson={'state': 'ON', 'brightness': int(brightness * 255)}) + await self._publish(topic=f"{attrs['root']}/light/kit_{chan}/command", messageJson={'state': 'ON', 'brightness': int(brightness * 255)}) - def _publishFrontScreenText(self, stmt): + async def _publishFrontScreenText(self, stmt): ignored = True for line in ['line1', 'line2', 'line3', 'line4']: if stmt[1] == ROOM[line]: ignored = False - self.settings.mqtt.publish(b'frontwindow/%s' % line.encode('ascii'), stmt[2].toPython()) + assert mqtt is not None + await mqtt.publish('frontwindow/%s' % line, stmt[2].toPython()) return ignored - @STATS.mqttPublish.time() - def _publish(self, topic: str, messageJson: object = None, message: str = None): + @MQTT_PUBLISH.time() + async def _publish(self, topic: str, messageJson: object = None, message: str | None = None): log.debug(f'mqtt.publish {topic} {message} {messageJson}') if messageJson is not None: message = json.dumps(messageJson) - self.settings.mqtt.publish(topic.encode('ascii'), message.encode('ascii')) + assert mqtt is not None + await mqtt.publish(topic, message) -if __name__ == '__main__': - arg = docopt(""" - Usage: rdf_to_mqtt.py [options] +def main(): - -v Verbose - """) - verboseLogging(arg['-v']) + async def start2(): + global mqtt + async with aiomqtt.Client(os.environ.get('MOSQUITTO', "mosquitto-ext"), 1883, client_id="rdf_to_mqtt-%s" % time.time(), keepalive=6) as mqtt: + log.info(f'connected to mqtt {mqtt}') + while True: + await asyncio.sleep(5) - mqtt = MqttClient(clientId='rdf_to_mqtt', brokerHost='mosquitto-ext.default.svc.cluster.local', brokerPort=1883) + def start(): + asyncio.create_task(start2()) - port = 10008 - reactor.listenTCP(port, - cyclone.web.Application([ - (r"/()", cyclone.web.StaticFileHandler, { - "path": ".", - "default_filename": "index.html" - }), - (r'/output', OutputPage), - (r'/stats/(.*)', StatsHandler, { - 'serverName': 'rdf_to_mqtt' - }), - ], - mqtt=mqtt, - debug=arg['-v']), - interface='::') - log.warn('serving on %s', port) + log.info('make app') + app = Starlette(debug=True, + on_startup=[start], + routes=[ + Route('/', StaticFiles(directory='.', html=True)), + Route("/output", OutputPage().put, methods=["PUT"]), + ]) + app.add_middleware(PrometheusMiddleware, app_name='environment') + app.add_route("/metrics", handle_metrics) + log.info('return app') + return app - reactor.run() + +app = main() \ No newline at end of file
--- a/service/rdf_to_mqtt/requirements.txt Fri Jun 30 22:11:06 2023 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -cyclone -rdflib-jsonld==0.4.0 -rdflib==4.2.2 -twisted-mqtt==0.3.6 -rx==1.6.1 -git+http://github.com/drewp/scales.git@448d59fb491b7631877528e7695a93553bfaaa93#egg=scales -docopt - -cycloneerr -patchablegraph==0.11.0 -rdfdb==0.21.0 -standardservice==0.6.0 -mqtt_client==0.7.0
--- a/service/rdf_to_mqtt/serv.n3 Fri Jun 30 22:11:06 2023 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -@prefix : <http://bigasterisk.com/ns/serv#> . -@prefix auth: <http://bigasterisk.com/ns/serv/auth#> . -@prefix serv: <http://bigasterisk.com/services/> . - - -serv:rdf_to_mqtt_image a :DockerImage; - :dockerFile "Dockerfile"; - :internalPort 10008 - . - - - -serv:rdf_to_mqtt a :Service; - :image serv:rdf_to_mqtt_image; - :path "/rdf_to_mqtt/"; - :openid auth:admin; - :serverHost "bang"; - :port 10008; - :prodDockerFlags ( - ); - :localRunDockerFlags ( - "-v" "`pwd`:/opt" - ); - :prodCmdline ("python3" "rdf_to_mqtt.py"); - :localRunCmdline ( "python3" "rdf_to_mqtt.py" "-v" ); -. -
--- a/service/rdf_to_mqtt/skaffold.yaml Fri Jun 30 22:11:06 2023 -0700 +++ b/service/rdf_to_mqtt/skaffold.yaml Mon Jul 10 17:37:58 2023 -0700 @@ -1,15 +1,17 @@ -apiVersion: skaffold/v2beta5 +apiVersion: skaffold/v4beta6 kind: Config metadata: name: rdf-to-mqtt build: + artifacts: + - image: bang5:5000/rdf_to_mqtt_image tagPolicy: dateTime: - format: "2006-01-02_15-04-05" - timezone: "Local" - artifacts: - - image: bang5:5000/rdf_to_mqtt_image + format: 2006-01-02_15-04-05 + timezone: Local +manifests: + rawYaml: + - deploy.yaml + - ingress.yaml deploy: - kubectl: - manifests: - - deploy.yaml + kubectl: {}