Compare commits
2 Commits
renovate/a
...
s-allius/u
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4535fbd32f | ||
|
|
c25fee4252 |
@@ -1,3 +1,2 @@
|
||||
[run]
|
||||
branch = True
|
||||
omit = app/src/web/templates/*.html.j2
|
||||
|
||||
@@ -6,9 +6,4 @@ PRIVAT_CONTAINER_REGISTRY=docker.io/<user>/
|
||||
|
||||
# registry for official container (preview, rc, rel)
|
||||
PUBLIC_CONTAINER_REGISTRY=ghcr.io/<user>/
|
||||
PUBLIC_CR_KEY=
|
||||
|
||||
# define serial number of GEN3PLUS devices for systemtests
|
||||
# the serialnumber are coded as 4-byte hex-strings
|
||||
SOLARMAN_INV_SNR='00000000'
|
||||
SOLARMAN_DCU_SNR='00000000'
|
||||
PUBLIC_CR_KEY=
|
||||
8
.github/workflows/python-app.yml
vendored
@@ -5,7 +5,7 @@ name: Python application
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main", "dev-*", "*/issue*", "releases/*" ]
|
||||
branches: [ "main", "dev-*", "*/issue*" ]
|
||||
paths-ignore:
|
||||
- '**.md' # Do no build on *.md changes
|
||||
- '**.yml' # Do no build on *.yml changes
|
||||
@@ -18,7 +18,7 @@ on:
|
||||
- '**.dockerfile' # Do no build on *.dockerfile changes
|
||||
- '**.sh' # Do no build on *.sh changes
|
||||
pull_request:
|
||||
branches: [ "main", "dev-*", "releases/*" ]
|
||||
branches: [ "main", "dev-*" ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
|
||||
- name: Set up Python 3.13
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.13"
|
||||
- name: Install dependencies
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
- name: Lint with flake8
|
||||
run: |
|
||||
# stop the build if there are Python syntax errors or undefined names
|
||||
flake8 . --count --select=E9,F63,F7,F82 --ignore=F821 --show-source --statistics
|
||||
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
|
||||
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
|
||||
flake8 --exit-zero --ignore=C901,E121,E123,E126,E133,E226,E241,E242,E704,W503,W504,W505 --format=pylint --output-file=output_flake.txt --exclude=*.pyc app/src/
|
||||
- name: Test with pytest
|
||||
|
||||
4
.gitignore
vendored
@@ -13,7 +13,3 @@ Doku/**
|
||||
.env
|
||||
.venv
|
||||
coverage.xml
|
||||
*.pot
|
||||
*.mo
|
||||
*.log
|
||||
*.log.*
|
||||
|
||||
@@ -1 +1 @@
|
||||
3.13.5
|
||||
3.13.2
|
||||
|
||||
36
CHANGELOG.md
@@ -7,42 +7,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [unreleased]
|
||||
|
||||
- Update dependency pytest-asyncio to v1.1.0
|
||||
- save task references, to avoid a task disappearing mid-execution
|
||||
- catch socket.gaierror exception and log this with info level
|
||||
- Update dependency coverage to v7.9.2
|
||||
- add-on: bump base-image to version 18.0.3
|
||||
- add-on: remove armhf and armv7 support
|
||||
- add-on: add links to config and log-file to the web-UI
|
||||
- fix some SonarQube warnings
|
||||
- remove unused 32-bit architectures
|
||||
- Babel don't build new po file if only the pot creation-date was changed
|
||||
- Improve Makefile
|
||||
- Update dependency pytest-asyncio to v1
|
||||
|
||||
## [0.14.1] - 2025-05-31
|
||||
|
||||
- handle missing MQTT addon [#438](https://github.com/s-allius/tsun-gen3-proxy/issues/438)
|
||||
|
||||
## [0.14.0] - 2025-05-29
|
||||
|
||||
- add-on: bump python to version 3.12.10-r1
|
||||
- set no of pv modules for MS800 GEN3PLUS inverters
|
||||
- fix the paths to copy the config.example.toml file during proxy start
|
||||
- add MQTT topic `dcu_power` for setting output power on DCUs
|
||||
- Update ghcr.io/hassio-addons/base Docker tag to v17.2.5
|
||||
- fix a lot of pytest-asyncio problems in the unit tests
|
||||
- Cleanup startup code for Quart and the Proxy
|
||||
- Redirect the hypercorn traces to a separate log-file
|
||||
- Configure the dashboard trace handler by the logging.ini file
|
||||
- Dashboard: add Notes page and table for important messages
|
||||
- Dashboard: add Log-File page
|
||||
- Dashboard: add Connection page
|
||||
- add web UI to add-on
|
||||
- allow `Y00` serial numbers for GEN3PLUS devices
|
||||
|
||||
## [0.13.0] - 2025-04-13
|
||||
|
||||
- update dependency python to 3.13
|
||||
- add initial support for TSUN MS-3000
|
||||
- add initial apparmor support [#293](https://github.com/s-allius/tsun-gen3-proxy/issues/293)
|
||||
|
||||
37
Makefile
@@ -1,37 +1,18 @@
|
||||
.PHONY: help build babel clean addon-dev addon-debug addon-rc addon-rel debug dev preview rc rel check-docker-compose install
|
||||
.PHONY: build clean addon-dev addon-debug addon-rc addon-rel debug dev preview rc rel check-docker-compose install
|
||||
|
||||
help: ## show help message
|
||||
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[$$()% a-zA-Z0-9_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
|
||||
|
||||
babel: ## build language files
|
||||
debug dev preview rc rel:
|
||||
$(MAKE) -C app $@
|
||||
|
||||
build:
|
||||
clean build:
|
||||
$(MAKE) -C ha_addons $@
|
||||
|
||||
clean: ## delete all built files
|
||||
$(MAKE) -C app $@
|
||||
$(MAKE) -C ha_addons $@
|
||||
|
||||
debug dev preview rc rel: ## build docker container in <dev|debg|rc|rel> version
|
||||
$(MAKE) -C app babel
|
||||
$(MAKE) -C app $@
|
||||
|
||||
addon-dev addon-debug addon-rc addon-rel: ## build HA add-on in <dev|debg|rc|rel> version
|
||||
$(MAKE) -C app babel
|
||||
addon-dev addon-debug addon-rc addon-rel:
|
||||
$(MAKE) -C ha_addons $(patsubst addon-%,%,$@)
|
||||
|
||||
check-docker-compose: ## check the docker-compose file
|
||||
check-docker-compose:
|
||||
docker-compose config -q
|
||||
|
||||
PY_VER := $(shell cat .python-version)
|
||||
|
||||
install: ## install requirements into the pyenv and switch to proper venv
|
||||
@pyenv local $(PY_VER) || { pyenv install $(PY_VER) && pyenv local $(PY_VER) || exit 1; }
|
||||
@pyenv exec pip install --upgrade pip
|
||||
@pyenv exec pip install -r requirements.txt
|
||||
@pyenv exec pip install -r requirements-test.txt
|
||||
pyenv exec python --version
|
||||
|
||||
run: ## run proxy locally out of the actual venv
|
||||
pyenv exec python app/src/server.py -c /app/src/cnf
|
||||
install:
|
||||
python3 -m pip install --upgrade pip
|
||||
python3 -m pip install -r requirements.txt
|
||||
python3 -m pip install -r requirements-test.txt
|
||||
@@ -8,7 +8,7 @@
|
||||
<p align="center">
|
||||
<a href="https://opensource.org/licenses/BSD-3-Clause"><img alt="License: BSD-3-Clause" src="https://img.shields.io/badge/License-BSD_3--Clause-green.svg"></a>
|
||||
<a href="https://www.python.org/downloads/release/python-3130/"><img alt="Supported Python versions" src="https://img.shields.io/badge/python-3.13-blue.svg"></a>
|
||||
<a href="https://aiomqtt.bo3hm.com/introduction.html"><img alt="Supported aiomqtt versions" src="https://img.shields.io/badge/aiomqtt-2.3.1-lightblue.svg"></a>
|
||||
<a href="https://sbtinstruments.github.io/aiomqtt/introduction.html"><img alt="Supported aiomqtt versions" src="https://img.shields.io/badge/aiomqtt-2.3.0-lightblue.svg"></a>
|
||||
<a href="https://libraries.io/pypi/aiocron"><img alt="Supported aiocron versions" src="https://img.shields.io/badge/aiocron-1.8-lightblue.svg"></a>
|
||||
<a href="https://toml.io/en/v1.0.0"><img alt="Supported toml versions" src="https://img.shields.io/badge/toml-1.0.0-lightblue.svg"></a>
|
||||
<br>
|
||||
@@ -141,7 +141,7 @@ No special configuration is required for the Docker container if it is built and
|
||||
|
||||
On the host, two directories (for log files and for config files) must be mapped. If necessary, the UID of the proxy process can be adjusted, which is also the owner of the log and configuration files.
|
||||
|
||||
A description of the configuration parameters can be found [here](https://github.com/s-allius/tsun-gen3-proxy/wiki/configuration-env#docker-compose-environment-variables)
|
||||
A description of the configuration parameters can be found [here](https://github.com/s-allius/tsun-gen3-proxy/wiki/Configuration-toml#docker-compose-environment-variables).
|
||||
|
||||
## Proxy Configuration
|
||||
|
||||
|
||||
@@ -2,6 +2,4 @@ tests/
|
||||
**/__pycache__
|
||||
*.pyc
|
||||
.DS_Store
|
||||
build.sh
|
||||
*.pot
|
||||
*.po
|
||||
build.sh
|
||||
@@ -1 +1 @@
|
||||
0.15.0
|
||||
0.13.0
|
||||
@@ -60,7 +60,6 @@ RUN python -m pip install --no-cache-dir --no-cache --no-index /root/wheels/* &&
|
||||
# copy the content of the local src and config directory to the working directory
|
||||
COPY --chmod=0700 entrypoint.sh /root/entrypoint.sh
|
||||
COPY src .
|
||||
COPY translations ./translations
|
||||
RUN echo ${VERSION} > /proxy-version.txt \
|
||||
&& date > /build-date.txt
|
||||
EXPOSE 5005 8127 10000
|
||||
|
||||
37
app/Makefile
@@ -6,23 +6,15 @@ IMAGE = tsun-gen3-proxy
|
||||
|
||||
|
||||
# Folders
|
||||
APP=.
|
||||
SRC=$(APP)/src
|
||||
# Folders for Babel translation
|
||||
BABEL_INPUT_JINJA=$(SRC)/web/templates
|
||||
BABEL_INPUT= $(foreach dir,$(BABEL_INPUT_JINJA),$(wildcard $(dir)/*.html.j2)) \
|
||||
|
||||
BABEL_TRANSLATIONS=$(APP)/translations
|
||||
SRC=.
|
||||
|
||||
export BUILD_DATE := ${shell date -Iminutes}
|
||||
VERSION := $(shell cat $(APP)/.version)
|
||||
VERSION := $(shell cat $(SRC)/.version)
|
||||
export MAJOR := $(shell echo $(VERSION) | cut -f1 -d.)
|
||||
|
||||
PUBLIC_URL := $(shell echo $(PUBLIC_CONTAINER_REGISTRY) | cut -f1 -d/)
|
||||
PUBLIC_USER :=$(shell echo $(PUBLIC_CONTAINER_REGISTRY) | cut -f2 -d/)
|
||||
|
||||
clean:
|
||||
rm -f $(BABEL_TRANSLATIONS)/*.pot
|
||||
|
||||
dev debug:
|
||||
@echo version: $(VERSION) build-date: $(BUILD_DATE) image: $(PRIVAT_CONTAINER_REGISTRY)$(IMAGE)
|
||||
@@ -30,16 +22,7 @@ dev debug:
|
||||
export IMAGE=$(PRIVAT_CONTAINER_REGISTRY)$(IMAGE) && \
|
||||
docker buildx bake -f docker-bake.hcl $@
|
||||
|
||||
rc:
|
||||
@[ "${RC}" ] || ( echo ">> RC is not set"; exit 1 )
|
||||
@echo version: $(VERSION) build-date: $(BUILD_DATE) image: $(PUBLIC_CONTAINER_REGISTRY)$(IMAGE)
|
||||
@echo login at $(PUBLIC_URL) as $(PUBLIC_USER)
|
||||
@DO_LOGIN="$(shell echo $(PUBLIC_CR_KEY) | docker login $(PUBLIC_URL) -u $(PUBLIC_USER) --password-stdin)"
|
||||
export VERSION=$(VERSION)-$@$(RC) && \
|
||||
export IMAGE=$(PUBLIC_CONTAINER_REGISTRY)$(IMAGE) && \
|
||||
docker buildx bake -f docker-bake.hcl $@
|
||||
|
||||
preview rel:
|
||||
preview rc rel:
|
||||
@echo version: $(VERSION) build-date: $(BUILD_DATE) image: $(PUBLIC_CONTAINER_REGISTRY)$(IMAGE)
|
||||
@echo login at $(PUBLIC_URL) as $(PUBLIC_USER)
|
||||
@DO_LOGIN="$(shell echo $(PUBLIC_CR_KEY) | docker login $(PUBLIC_URL) -u $(PUBLIC_USER) --password-stdin)"
|
||||
@@ -47,17 +30,5 @@ preview rel:
|
||||
export IMAGE=$(PUBLIC_CONTAINER_REGISTRY)$(IMAGE) && \
|
||||
docker buildx bake -f docker-bake.hcl $@
|
||||
|
||||
babel: $(BABEL_TRANSLATIONS)/de/LC_MESSAGES/messages.mo $(BABEL_TRANSLATIONS)/de/LC_MESSAGES/messages.po $(BABEL_TRANSLATIONS)/messages.pot
|
||||
|
||||
$(BABEL_TRANSLATIONS)/%.pot : $(SRC)/.babel.cfg $(BABEL_INPUT)
|
||||
@mkdir -p $(@D)
|
||||
@pybabel extract -F $< --project=$(IMAGE) --version=$(VERSION) -o $@ $(SRC)
|
||||
|
||||
$(BABEL_TRANSLATIONS)/%/LC_MESSAGES/messages.po : $(BABEL_TRANSLATIONS)/messages.pot
|
||||
@mkdir -p $(@D)
|
||||
@pybabel update --init-missing --ignore-pot-creation-date -i $< -d $(BABEL_TRANSLATIONS) -l $*
|
||||
|
||||
$(BABEL_TRANSLATIONS)/%/LC_MESSAGES/messages.mo : $(BABEL_TRANSLATIONS)/%/LC_MESSAGES/messages.po
|
||||
@pybabel compile -d $(BABEL_TRANSLATIONS) -l $*
|
||||
|
||||
.PHONY: babel clean debug dev preview rc rel
|
||||
.PHONY: debug dev preview rc rel
|
||||
|
||||
@@ -29,17 +29,17 @@ target "_common" {
|
||||
"type =sbom,generator=docker/scout-sbom-indexer:latest"
|
||||
]
|
||||
annotations = [
|
||||
"index,manifest-descriptor:org.opencontainers.image.title=TSUN-Proxy",
|
||||
"index,manifest-descriptor:org.opencontainers.image.authors=Stefan Allius",
|
||||
"index,manifest-descriptor:org.opencontainers.image.created=${BUILD_DATE}",
|
||||
"index,manifest-descriptor:org.opencontainers.image.version=${VERSION}",
|
||||
"index,manifest-descriptor:org.opencontainers.image.revision=${BRANCH}",
|
||||
"index,manifest-descriptor:org.opencontainers.image.description=${DESCRIPTION}",
|
||||
"index:org.opencontainers.image.title=TSUN Gen3 Proxy",
|
||||
"index:org.opencontainers.image.authors=Stefan Allius",
|
||||
"index:org.opencontainers.image.created=${BUILD_DATE}",
|
||||
"index:org.opencontainers.image.version=${VERSION}",
|
||||
"index:org.opencontainers.image.revision=${BRANCH}",
|
||||
"index:org.opencontainers.image.description=${DESCRIPTION}",
|
||||
"index:org.opencontainers.image.licenses=BSD-3-Clause",
|
||||
"index:org.opencontainers.image.source=https://github.com/s-allius/tsun-gen3-proxy"
|
||||
]
|
||||
labels = {
|
||||
"org.opencontainers.image.title" = "TSUN-Proxy"
|
||||
"org.opencontainers.image.title" = "TSUN Gen3 Proxy"
|
||||
"org.opencontainers.image.authors" = "Stefan Allius"
|
||||
"org.opencontainers.image.created" = "${BUILD_DATE}"
|
||||
"org.opencontainers.image.version" = "${VERSION}"
|
||||
@@ -53,7 +53,7 @@ target "_common" {
|
||||
]
|
||||
|
||||
no-cache = false
|
||||
platforms = ["linux/amd64", "linux/arm64"]
|
||||
platforms = ["linux/amd64", "linux/arm64", "linux/arm/v7"]
|
||||
}
|
||||
|
||||
target "_debug" {
|
||||
|
||||
@@ -4,380 +4,368 @@
|
||||
<!-- Generated by graphviz version 2.40.1 (20161225.0304)
|
||||
-->
|
||||
<!-- Title: G Pages: 1 -->
|
||||
<svg width="548pt" height="2000pt"
|
||||
viewBox="0.00 0.00 548.12 2000.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<svg width="539pt" height="2000pt"
|
||||
viewBox="0.00 0.00 538.57 2000.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 1996)">
|
||||
<title>G</title>
|
||||
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-1996 544.1155,-1996 544.1155,4 -4,4"/>
|
||||
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-1996 534.566,-1996 534.566,4 -4,4"/>
|
||||
<!-- A0 -->
|
||||
<g id="node1" class="node">
|
||||
<title>A0</title>
|
||||
<polygon fill="#fff8dc" stroke="#000000" points="239.7476,-1972 141.4834,-1972 141.4834,-1928 245.7476,-1928 245.7476,-1966 239.7476,-1972"/>
|
||||
<polyline fill="none" stroke="#000000" points="239.7476,-1972 239.7476,-1966 "/>
|
||||
<polyline fill="none" stroke="#000000" points="245.7476,-1966 239.7476,-1966 "/>
|
||||
<text text-anchor="middle" x="193.6155" y="-1959" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Example of</text>
|
||||
<text text-anchor="middle" x="193.6155" y="-1947" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">instantiation for a</text>
|
||||
<text text-anchor="middle" x="193.6155" y="-1935" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">GEN3 inverter!</text>
|
||||
<polygon fill="#fff8dc" stroke="#000000" points="98.1981,-1972 -.0661,-1972 -.0661,-1928 104.1981,-1928 104.1981,-1966 98.1981,-1972"/>
|
||||
<polyline fill="none" stroke="#000000" points="98.1981,-1972 98.1981,-1966 "/>
|
||||
<polyline fill="none" stroke="#000000" points="104.1981,-1966 98.1981,-1966 "/>
|
||||
<text text-anchor="middle" x="52.066" y="-1959" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Example of</text>
|
||||
<text text-anchor="middle" x="52.066" y="-1947" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">instantiation for a</text>
|
||||
<text text-anchor="middle" x="52.066" y="-1935" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">GEN3 inverter!</text>
|
||||
</g>
|
||||
<!-- A1 -->
|
||||
<g id="node2" class="node">
|
||||
<title>A1</title>
|
||||
<polygon fill="none" stroke="#000000" points="263.6155,-1960 263.6155,-1992 379.6155,-1992 379.6155,-1960 263.6155,-1960"/>
|
||||
<text text-anchor="start" x="273.2645" y="-1973" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><<AbstractIterMeta>></text>
|
||||
<polygon fill="none" stroke="#000000" points="263.6155,-1940 263.6155,-1960 379.6155,-1960 379.6155,-1940 263.6155,-1940"/>
|
||||
<polygon fill="none" stroke="#000000" points="263.6155,-1908 263.6155,-1940 379.6155,-1940 379.6155,-1908 263.6155,-1908"/>
|
||||
<text text-anchor="start" x="300.2255" y="-1921" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__iter__()</text>
|
||||
</g>
|
||||
<!-- A15 -->
|
||||
<g id="node16" class="node">
|
||||
<title>A15</title>
|
||||
<polygon fill="none" stroke="#000000" points="276.6155,-1748 276.6155,-1780 366.6155,-1780 366.6155,-1748 276.6155,-1748"/>
|
||||
<text text-anchor="start" x="286.322" y="-1761" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><<ProtocolIfc>></text>
|
||||
<polygon fill="none" stroke="#000000" points="276.6155,-1716 276.6155,-1748 366.6155,-1748 366.6155,-1716 276.6155,-1716"/>
|
||||
<text text-anchor="start" x="302.449" y="-1729" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_registry</text>
|
||||
<polygon fill="none" stroke="#000000" points="276.6155,-1684 276.6155,-1716 366.6155,-1716 366.6155,-1684 276.6155,-1684"/>
|
||||
<text text-anchor="start" x="306.618" y="-1697" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A1->A15 -->
|
||||
<g id="edge15" class="edge">
|
||||
<title>A1->A15</title>
|
||||
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M321.6155,-1897.756C321.6155,-1862.0883 321.6155,-1815.1755 321.6155,-1780.3644"/>
|
||||
<polygon fill="none" stroke="#000000" points="318.1156,-1897.9674 321.6155,-1907.9674 325.1156,-1897.9674 318.1156,-1897.9674"/>
|
||||
</g>
|
||||
<!-- A2 -->
|
||||
<g id="node3" class="node">
|
||||
<title>A2</title>
|
||||
<polygon fill="none" stroke="#000000" points="77.6155,-662 77.6155,-694 175.6155,-694 175.6155,-662 77.6155,-662"/>
|
||||
<text text-anchor="start" x="98.2755" y="-675" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterBase</text>
|
||||
<polygon fill="none" stroke="#000000" points="77.6155,-606 77.6155,-662 175.6155,-662 175.6155,-606 77.6155,-606"/>
|
||||
<text text-anchor="start" x="116.6125" y="-643" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="87.1685" y="-631" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote:StreamPtr</text>
|
||||
<text text-anchor="start" x="92.4475" y="-619" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local:StreamPtr</text>
|
||||
<polygon fill="none" stroke="#000000" points="77.6155,-550 77.6155,-606 175.6155,-606 175.6155,-550 77.6155,-550"/>
|
||||
<text text-anchor="start" x="91.0575" y="-587" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">create_remote()</text>
|
||||
<text text-anchor="start" x="111.618" y="-563" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A3 -->
|
||||
<g id="node4" class="node">
|
||||
<title>A3</title>
|
||||
<polygon fill="none" stroke="#000000" points="75.3469,-320 -.1159,-320 -.1159,-284 75.3469,-284 75.3469,-320"/>
|
||||
<text text-anchor="middle" x="37.6155" y="-299" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterG3</text>
|
||||
</g>
|
||||
<!-- A2->A3 -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>A2->A3</title>
|
||||
<path fill="none" stroke="#000000" d="M103.8,-539.9668C83.1352,-465.6664 54.2132,-361.677 42.6665,-320.1609"/>
|
||||
<polygon fill="none" stroke="#000000" points="100.4796,-541.0903 106.5312,-549.7868 107.2236,-539.2146 100.4796,-541.0903"/>
|
||||
</g>
|
||||
<!-- A4 -->
|
||||
<g id="node5" class="node">
|
||||
<title>A4</title>
|
||||
<polygon fill="none" stroke="#000000" points="189.9521,-320 93.2789,-320 93.2789,-284 189.9521,-284 189.9521,-320"/>
|
||||
<text text-anchor="middle" x="141.6155" y="-299" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local:StreamPtr</text>
|
||||
</g>
|
||||
<!-- A2->A4 -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>A2->A4</title>
|
||||
<path fill="none" stroke="#000000" d="M130.5679,-537.6831C133.7849,-469.0527 138.1335,-376.283 140.2896,-330.2853"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="130.5625,-537.7999 134.2771,-543.9807 130.0005,-549.7868 126.2859,-543.606 130.5625,-537.7999"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="140.7642,-320.1609 144.7909,-330.3606 140.53,-325.1554 140.2959,-330.1499 140.2959,-330.1499 140.2959,-330.1499 140.53,-325.1554 135.8008,-329.9391 140.7642,-320.1609 140.7642,-320.1609"/>
|
||||
</g>
|
||||
<!-- A5 -->
|
||||
<g id="node6" class="node">
|
||||
<title>A5</title>
|
||||
<polygon fill="none" stroke="#000000" points="315.0096,-320 208.2214,-320 208.2214,-284 315.0096,-284 315.0096,-320"/>
|
||||
<text text-anchor="middle" x="261.6155" y="-299" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote:StreamPtr</text>
|
||||
</g>
|
||||
<!-- A2->A5 -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>A2->A5</title>
|
||||
<path fill="none" stroke="#000000" d="M157.861,-538.7126C166.3035,-516.9056 175.6035,-493.4873 184.6155,-472 205.944,-421.1467 232.9474,-362.7699 248.6524,-329.3512"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="157.8454,-538.7533 159.4203,-545.7903 153.5304,-549.9506 151.9554,-542.9136 157.8454,-538.7533"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="252.9567,-320.2155 252.7653,-331.1797 250.8256,-324.7387 248.6945,-329.2618 248.6945,-329.2618 248.6945,-329.2618 250.8256,-324.7387 244.6237,-327.3438 252.9567,-320.2155 252.9567,-320.2155"/>
|
||||
</g>
|
||||
<!-- A9 -->
|
||||
<g id="node10" class="node">
|
||||
<title>A9</title>
|
||||
<polygon fill="none" stroke="#000000" points="128.6155,-100 128.6155,-132 306.6155,-132 306.6155,-100 128.6155,-100"/>
|
||||
<text text-anchor="start" x="173.167" y="-113" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStreamServer</text>
|
||||
<polygon fill="none" stroke="#000000" points="128.6155,-68 128.6155,-100 306.6155,-100 306.6155,-68 128.6155,-68"/>
|
||||
<text text-anchor="start" x="185.3865" y="-81" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">create_remote</text>
|
||||
<polygon fill="none" stroke="#000000" points="128.6155,0 128.6155,-68 306.6155,-68 306.6155,0 128.6155,0"/>
|
||||
<text text-anchor="start" x="169.273" y="-49" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>server_loop()</text>
|
||||
<text text-anchor="start" x="160.104" y="-37" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>_async_forward()</text>
|
||||
<text text-anchor="start" x="138.4245" y="-25" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>publish_outstanding_mqtt()</text>
|
||||
<text text-anchor="start" x="202.618" y="-13" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A4->A9 -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>A4->A9</title>
|
||||
<path fill="none" stroke="#000000" d="M151.2355,-272.1274C161.7441,-239.4955 178.9835,-185.9626 193.26,-141.6303"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="151.1313,-272.451 153.0996,-279.3883 147.4529,-283.8733 145.4847,-276.936 151.1313,-272.451"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="196.3509,-132.0321 197.5689,-142.9302 194.8182,-136.7914 193.2855,-141.5507 193.2855,-141.5507 193.2855,-141.5507 194.8182,-136.7914 189.0022,-140.1713 196.3509,-132.0321 196.3509,-132.0321"/>
|
||||
</g>
|
||||
<!-- A10 -->
|
||||
<g id="node11" class="node">
|
||||
<title>A10</title>
|
||||
<polygon fill="none" stroke="#000000" points="362.6155,-82 362.6155,-114 500.6155,-114 500.6155,-82 362.6155,-82"/>
|
||||
<text text-anchor="start" x="389.1125" y="-95" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStreamClient</text>
|
||||
<polygon fill="none" stroke="#000000" points="362.6155,-62 362.6155,-82 500.6155,-82 500.6155,-62 362.6155,-62"/>
|
||||
<polygon fill="none" stroke="#000000" points="362.6155,-18 362.6155,-62 500.6155,-62 500.6155,-18 362.6155,-18"/>
|
||||
<text text-anchor="start" x="385.4935" y="-43" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>client_loop()</text>
|
||||
<text text-anchor="start" x="372.4395" y="-31" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>_async_forward())</text>
|
||||
</g>
|
||||
<!-- A5->A10 -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>A5->A10</title>
|
||||
<path fill="none" stroke="#000000" d="M269.2148,-283.6405C279.6962,-259.3121 299.996,-215.5582 323.6155,-182 338.3046,-161.1299 356.5265,-140.1557 373.793,-121.8925"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="381.1214,-114.2395 377.4553,-124.5745 377.6632,-117.8508 374.2051,-121.4621 374.2051,-121.4621 374.2051,-121.4621 377.6632,-117.8508 370.9549,-118.3498 381.1214,-114.2395 381.1214,-114.2395"/>
|
||||
<text text-anchor="middle" x="268.7308" y="-260.6464" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
|
||||
</g>
|
||||
<!-- A6 -->
|
||||
<g id="node7" class="node">
|
||||
<title>A6</title>
|
||||
<polygon fill="none" stroke="#000000" points="396.6155,-1114 396.6155,-1146 513.6155,-1146 513.6155,-1114 396.6155,-1114"/>
|
||||
<text text-anchor="start" x="424.5445" y="-1127" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><<AsyncIfc>></text>
|
||||
<polygon fill="none" stroke="#000000" points="396.6155,-1094 396.6155,-1114 513.6155,-1114 513.6155,-1094 396.6155,-1094"/>
|
||||
<polygon fill="none" stroke="#000000" points="396.6155,-822 396.6155,-1094 513.6155,-1094 513.6155,-822 396.6155,-822"/>
|
||||
<text text-anchor="start" x="424.5515" y="-1075" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">set_node_id()</text>
|
||||
<text text-anchor="start" x="422.8815" y="-1063" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">get_conn_no()</text>
|
||||
<text text-anchor="start" x="436.779" y="-1039" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_add()</text>
|
||||
<text text-anchor="start" x="434.5595" y="-1027" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_flush()</text>
|
||||
<text text-anchor="start" x="438.169" y="-1015" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_get()</text>
|
||||
<text text-anchor="start" x="434.279" y="-1003" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_peek()</text>
|
||||
<text text-anchor="start" x="438.449" y="-991" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_log()</text>
|
||||
<text text-anchor="start" x="434.2845" y="-979" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_clear()</text>
|
||||
<text text-anchor="start" x="438.449" y="-967" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_len()</text>
|
||||
<text text-anchor="start" x="432.89" y="-943" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_add()</text>
|
||||
<text text-anchor="start" x="434.56" y="-931" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_log()</text>
|
||||
<text text-anchor="start" x="437.894" y="-919" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_get()</text>
|
||||
<text text-anchor="start" x="434.004" y="-907" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_peek()</text>
|
||||
<text text-anchor="start" x="438.174" y="-895" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_log()</text>
|
||||
<text text-anchor="start" x="434.0095" y="-883" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_clear()</text>
|
||||
<text text-anchor="start" x="438.174" y="-871" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_len()</text>
|
||||
<text text-anchor="start" x="430.1145" y="-859" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_set_cb()</text>
|
||||
<text text-anchor="start" x="406.495" y="-835" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">prot_set_timeout_cb()</text>
|
||||
</g>
|
||||
<!-- A7 -->
|
||||
<g id="node8" class="node">
|
||||
<title>A7</title>
|
||||
<polygon fill="none" stroke="#000000" points="447.6155,-652 447.6155,-684 540.6155,-684 540.6155,-652 447.6155,-652"/>
|
||||
<text text-anchor="start" x="465.7795" y="-665" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncIfcImpl</text>
|
||||
<polygon fill="none" stroke="#000000" points="447.6155,-560 447.6155,-652 540.6155,-652 540.6155,-560 447.6155,-560"/>
|
||||
<text text-anchor="start" x="457.1635" y="-633" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_fifo:ByteFifo</text>
|
||||
<text text-anchor="start" x="461.0525" y="-621" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_fifo:ByteFifo</text>
|
||||
<text text-anchor="start" x="460.7775" y="-609" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_fifo:ByteFifo</text>
|
||||
<text text-anchor="start" x="460.2115" y="-597" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">conn_no:Count</text>
|
||||
<text text-anchor="start" x="476.329" y="-585" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">node_id</text>
|
||||
<text text-anchor="start" x="469.665" y="-573" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">timeout_cb</text>
|
||||
</g>
|
||||
<!-- A6->A7 -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>A6->A7</title>
|
||||
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M473.1735,-811.7434C478.1009,-766.0069 483.1088,-719.5241 486.9345,-684.013"/>
|
||||
<polygon fill="none" stroke="#000000" points="469.682,-811.4771 472.0907,-821.7945 476.6418,-812.227 469.682,-811.4771"/>
|
||||
</g>
|
||||
<!-- A8 -->
|
||||
<g id="node9" class="node">
|
||||
<title>A8</title>
|
||||
<polygon fill="none" stroke="#000000" points="418.6155,-390 418.6155,-422 520.6155,-422 520.6155,-390 418.6155,-390"/>
|
||||
<text text-anchor="start" x="439.8895" y="-403" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStream</text>
|
||||
<polygon fill="none" stroke="#000000" points="418.6155,-310 418.6155,-390 520.6155,-390 520.6155,-310 418.6155,-310"/>
|
||||
<text text-anchor="start" x="455.1685" y="-371" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">reader</text>
|
||||
<text text-anchor="start" x="457.3985" y="-359" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">writer</text>
|
||||
<text text-anchor="start" x="459.6125" y="-347" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="455.1685" y="-335" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">r_addr</text>
|
||||
<text text-anchor="start" x="455.7235" y="-323" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">l_addr</text>
|
||||
<polygon fill="none" stroke="#000000" points="418.6155,-182 418.6155,-310 520.6155,-310 520.6155,-182 418.6155,-182"/>
|
||||
<text text-anchor="start" x="441.2695" y="-279" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>loop</text>
|
||||
<text text-anchor="start" x="457.3975" y="-267" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">disc()</text>
|
||||
<text text-anchor="start" x="454.618" y="-255" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
<text text-anchor="start" x="450.1695" y="-243" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
|
||||
<text text-anchor="start" x="434.886" y="-219" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_read()</text>
|
||||
<text text-anchor="start" x="434.3365" y="-207" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_write()</text>
|
||||
<text text-anchor="start" x="428.2225" y="-195" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_forward()</text>
|
||||
</g>
|
||||
<!-- A7->A8 -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>A7->A8</title>
|
||||
<path fill="none" stroke="#000000" d="M488.1838,-549.5774C485.3646,-511.9877 481.8463,-465.0771 478.6327,-422.2295"/>
|
||||
<polygon fill="none" stroke="#000000" points="484.7214,-550.2112 488.9596,-559.9214 491.7018,-549.6876 484.7214,-550.2112"/>
|
||||
</g>
|
||||
<!-- A8->A9 -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>A8->A9</title>
|
||||
<path fill="none" stroke="#000000" d="M412.0877,-185.8777C410.9473,-184.56 409.7899,-183.2666 408.6155,-182 380.1271,-151.2753 341.6819,-125.829 306.7513,-106.6759"/>
|
||||
<polygon fill="none" stroke="#000000" points="409.4058,-188.1271 418.4338,-193.672 414.834,-183.7074 409.4058,-188.1271"/>
|
||||
</g>
|
||||
<!-- A8->A10 -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>A8->A10</title>
|
||||
<path fill="none" stroke="#000000" d="M448.6523,-171.8077C445.3431,-151.2556 442.1142,-131.2022 439.3729,-114.1772"/>
|
||||
<polygon fill="none" stroke="#000000" points="445.2363,-172.6095 450.2815,-181.9259 452.1472,-171.4966 445.2363,-172.6095"/>
|
||||
</g>
|
||||
<!-- A11 -->
|
||||
<g id="node12" class="node">
|
||||
<title>A11</title>
|
||||
<polygon fill="none" stroke="#000000" points="193.6155,-740 193.6155,-772 307.6155,-772 307.6155,-740 193.6155,-740"/>
|
||||
<text text-anchor="start" x="236.7235" y="-753" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Talent</text>
|
||||
<polygon fill="none" stroke="#000000" points="193.6155,-600 193.6155,-740 307.6155,-740 307.6155,-600 193.6155,-600"/>
|
||||
<text text-anchor="start" x="231.4385" y="-721" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">conn_no</text>
|
||||
<text text-anchor="start" x="240.6125" y="-709" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="203.3785" y="-685" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">await_conn_resp_cnt</text>
|
||||
<text text-anchor="start" x="238.393" y="-673" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">id_str</text>
|
||||
<text text-anchor="start" x="219.2155" y="-661" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">contact_name</text>
|
||||
<text text-anchor="start" x="222.5555" y="-649" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">contact_mail</text>
|
||||
<text text-anchor="start" x="226.16" y="-637" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">db:InfosG3</text>
|
||||
<text text-anchor="start" x="224.4995" y="-625" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb:Modbus</text>
|
||||
<text text-anchor="start" x="236.7275" y="-613" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">switch</text>
|
||||
<polygon fill="none" stroke="#000000" points="193.6155,-472 193.6155,-600 307.6155,-600 307.6155,-472 193.6155,-472"/>
|
||||
<text text-anchor="start" x="208.108" y="-581" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_contact_info()</text>
|
||||
<text text-anchor="start" x="210.048" y="-569" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_ota_update()</text>
|
||||
<text text-anchor="start" x="215.892" y="-557" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_get_time()</text>
|
||||
<text text-anchor="start" x="203.944" y="-545" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_collector_data()</text>
|
||||
<text text-anchor="start" x="205.889" y="-533" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_inverter_data()</text>
|
||||
<text text-anchor="start" x="215.056" y="-521" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_unknown()</text>
|
||||
<text text-anchor="start" x="231.1695" y="-497" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
|
||||
<text text-anchor="start" x="235.618" y="-485" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A11->A4 -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>A11->A4</title>
|
||||
<path fill="none" stroke="#000000" d="M196.2254,-462.3225C179.1579,-412.2162 162.0761,-362.0677 151.6753,-331.5332"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="199.4666,-471.8382 191.9826,-463.8233 197.8544,-467.1053 196.2422,-462.3723 196.2422,-462.3723 196.2422,-462.3723 197.8544,-467.1053 200.5019,-460.9213 199.4666,-471.8382 199.4666,-471.8382"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="151.6435,-331.4398 145.9225,-327.05 147.7742,-320.0807 153.4952,-324.4705 151.6435,-331.4398"/>
|
||||
</g>
|
||||
<!-- A11->A5 -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>A11->A5</title>
|
||||
<path fill="none" stroke="#000000" d="M256.1287,-461.6172C258.0803,-404.8425 260.0297,-348.132 260.994,-320.0807"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="255.7773,-471.8382 251.6236,-461.6895 255.9491,-466.8412 256.121,-461.8441 256.121,-461.8441 256.121,-461.8441 255.9491,-466.8412 260.6183,-461.9988 255.7773,-471.8382 255.7773,-471.8382"/>
|
||||
<text text-anchor="middle" x="268.8186" y="-335.4866" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
|
||||
</g>
|
||||
<!-- A13 -->
|
||||
<g id="node14" class="node">
|
||||
<title>A13</title>
|
||||
<polygon fill="none" stroke="#000000" points="333.6155,-318 333.6155,-350 400.6155,-350 400.6155,-318 333.6155,-318"/>
|
||||
<text text-anchor="start" x="349.6085" y="-331" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InfosG3</text>
|
||||
<polygon fill="none" stroke="#000000" points="333.6155,-298 333.6155,-318 400.6155,-318 400.6155,-298 333.6155,-298"/>
|
||||
<polygon fill="none" stroke="#000000" points="333.6155,-254 333.6155,-298 400.6155,-298 400.6155,-254 333.6155,-254"/>
|
||||
<text text-anchor="start" x="343.4995" y="-279" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_confs()</text>
|
||||
<text text-anchor="start" x="351.2835" y="-267" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">parse()</text>
|
||||
</g>
|
||||
<!-- A11->A13 -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>A11->A13</title>
|
||||
<path fill="none" stroke="#000000" d="M305.5203,-471.8728C311.6394,-455.0532 317.7699,-438.1631 323.6155,-422 330.9569,-401.7009 338.9463,-379.4498 346.0242,-359.681"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="349.4187,-350.1951 350.2862,-361.1266 347.734,-354.9028 346.0494,-359.6104 346.0494,-359.6104 346.0494,-359.6104 347.734,-354.9028 341.8125,-358.0942 349.4187,-350.1951 349.4187,-350.1951"/>
|
||||
</g>
|
||||
<!-- A12 -->
|
||||
<g id="node13" class="node">
|
||||
<title>A12</title>
|
||||
<polygon fill="none" stroke="#000000" points="326.6155,-710 326.6155,-742 429.6155,-742 429.6155,-710 326.6155,-710"/>
|
||||
<text text-anchor="start" x="367.2775" y="-723" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Infos</text>
|
||||
<polygon fill="none" stroke="#000000" points="326.6155,-654 326.6155,-710 429.6155,-710 429.6155,-654 326.6155,-654"/>
|
||||
<text text-anchor="start" x="370.057" y="-691" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">stat</text>
|
||||
<text text-anchor="start" x="345.6015" y="-679" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">new_stat_data</text>
|
||||
<text text-anchor="start" x="359.219" y="-667" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">info_dev</text>
|
||||
<polygon fill="none" stroke="#000000" points="326.6155,-502 326.6155,-654 429.6155,-654 429.6155,-502 326.6155,-502"/>
|
||||
<text text-anchor="start" x="353.951" y="-635" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">static_init()</text>
|
||||
<text text-anchor="start" x="352" y="-623" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dev_value()</text>
|
||||
<text text-anchor="start" x="348.946" y="-611" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inc_counter()</text>
|
||||
<text text-anchor="start" x="347.276" y="-599" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dec_counter()</text>
|
||||
<text text-anchor="start" x="345.3255" y="-587" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_proxy_conf</text>
|
||||
<text text-anchor="start" x="360.3285" y="-575" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_conf</text>
|
||||
<text text-anchor="start" x="353.1095" y="-563" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_remove</text>
|
||||
<text text-anchor="start" x="354.49" y="-551" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">update_db</text>
|
||||
<text text-anchor="start" x="338.6525" y="-539" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">set_db_def_value</text>
|
||||
<text text-anchor="start" x="348.101" y="-527" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">get_db_value</text>
|
||||
<text text-anchor="start" x="336.438" y="-515" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ignore_this_device</text>
|
||||
</g>
|
||||
<!-- A12->A13 -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>A12->A13</title>
|
||||
<path fill="none" stroke="#000000" d="M373.1357,-491.6786C371.4196,-441.7544 369.5661,-387.8351 368.2756,-350.293"/>
|
||||
<polygon fill="none" stroke="#000000" points="369.6466,-492.0596 373.4882,-501.9334 376.6425,-491.819 369.6466,-492.0596"/>
|
||||
<polygon fill="none" stroke="#000000" points="122.066,-1960 122.066,-1992 238.066,-1992 238.066,-1960 122.066,-1960"/>
|
||||
<text text-anchor="start" x="131.715" y="-1973" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><<AbstractIterMeta>></text>
|
||||
<polygon fill="none" stroke="#000000" points="122.066,-1940 122.066,-1960 238.066,-1960 238.066,-1940 122.066,-1940"/>
|
||||
<polygon fill="none" stroke="#000000" points="122.066,-1908 122.066,-1940 238.066,-1940 238.066,-1908 122.066,-1908"/>
|
||||
<text text-anchor="start" x="158.676" y="-1921" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__iter__()</text>
|
||||
</g>
|
||||
<!-- A14 -->
|
||||
<g id="node15" class="node">
|
||||
<title>A14</title>
|
||||
<polygon fill="none" stroke="#000000" points="297.6155,-1524 297.6155,-1556 446.6155,-1556 446.6155,-1524 297.6155,-1524"/>
|
||||
<text text-anchor="start" x="351.833" y="-1537" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Message</text>
|
||||
<polygon fill="none" stroke="#000000" points="297.6155,-1300 297.6155,-1524 446.6155,-1524 446.6155,-1300 297.6155,-1300"/>
|
||||
<text text-anchor="start" x="335.442" y="-1505" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">server_side:bool</text>
|
||||
<text text-anchor="start" x="345.9995" y="-1493" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb:Modbus</text>
|
||||
<text text-anchor="start" x="346.834" y="-1481" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ifc:AsyncIfc</text>
|
||||
<text text-anchor="start" x="354.329" y="-1469" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">node_id</text>
|
||||
<text text-anchor="start" x="332.6585" y="-1457" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">header_valid:bool</text>
|
||||
<text text-anchor="start" x="347.1055" y="-1445" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">header_len</text>
|
||||
<text text-anchor="start" x="352.9395" y="-1433" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">data_len</text>
|
||||
<text text-anchor="start" x="350.44" y="-1421" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">unique_id</text>
|
||||
<text text-anchor="start" x="344.3305" y="-1409" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sug_area:str</text>
|
||||
<text text-anchor="start" x="341.2715" y="-1397" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">new_data:dict</text>
|
||||
<text text-anchor="start" x="348.2155" y="-1385" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">state:State</text>
|
||||
<text text-anchor="start" x="321.82" y="-1373" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">shutdown_started:bool</text>
|
||||
<text text-anchor="start" x="341" y="-1361" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">modbus_elms</text>
|
||||
<text text-anchor="start" x="337.1225" y="-1349" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb_timer:Timer</text>
|
||||
<text text-anchor="start" x="346.0005" y="-1337" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb_timeout</text>
|
||||
<text text-anchor="start" x="335.168" y="-1325" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb_first_timeout</text>
|
||||
<text text-anchor="start" x="326.2695" y="-1313" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">modbus_polling:bool</text>
|
||||
<polygon fill="none" stroke="#000000" points="297.6155,-1196 297.6155,-1300 446.6155,-1300 446.6155,-1196 297.6155,-1196"/>
|
||||
<text text-anchor="start" x="321" y="-1281" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_set_mqtt_timestamp()</text>
|
||||
<text text-anchor="start" x="349.6155" y="-1269" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_timeout()</text>
|
||||
<text text-anchor="start" x="322.383" y="-1257" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_send_modbus_cmd()</text>
|
||||
<text text-anchor="start" x="307.375" y="-1245" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async> end_modbus_cmd()</text>
|
||||
<text text-anchor="start" x="357.118" y="-1233" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
<text text-anchor="start" x="342.946" y="-1221" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inc_counter()</text>
|
||||
<text text-anchor="start" x="341.276" y="-1209" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dec_counter()</text>
|
||||
<polygon fill="none" stroke="#000000" points="135.066,-1748 135.066,-1780 225.066,-1780 225.066,-1748 135.066,-1748"/>
|
||||
<text text-anchor="start" x="144.7725" y="-1761" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><<ProtocolIfc>></text>
|
||||
<polygon fill="none" stroke="#000000" points="135.066,-1716 135.066,-1748 225.066,-1748 225.066,-1716 135.066,-1716"/>
|
||||
<text text-anchor="start" x="160.8995" y="-1729" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_registry</text>
|
||||
<polygon fill="none" stroke="#000000" points="135.066,-1684 135.066,-1716 225.066,-1716 225.066,-1684 135.066,-1684"/>
|
||||
<text text-anchor="start" x="165.0685" y="-1697" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A14->A6 -->
|
||||
<!-- A1->A14 -->
|
||||
<g id="edge14" class="edge">
|
||||
<title>A14->A6</title>
|
||||
<path fill="none" stroke="#000000" d="M409.7752,-1195.7758C412.5746,-1182.5547 415.3943,-1169.2373 418.1831,-1156.0662"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="420.3088,-1146.0268 422.6397,-1156.7421 419.2731,-1150.9183 418.2373,-1155.8099 418.2373,-1155.8099 418.2373,-1155.8099 419.2731,-1150.9183 413.8349,-1154.8777 420.3088,-1146.0268 420.3088,-1146.0268"/>
|
||||
<text text-anchor="middle" x="405.2609" y="-1173.292" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">use</text>
|
||||
<title>A1->A14</title>
|
||||
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M180.066,-1897.756C180.066,-1862.0883 180.066,-1815.1755 180.066,-1780.3644"/>
|
||||
<polygon fill="none" stroke="#000000" points="176.5661,-1897.9674 180.066,-1907.9674 183.5661,-1897.9674 176.5661,-1897.9674"/>
|
||||
</g>
|
||||
<!-- A14->A11 -->
|
||||
<g id="edge17" class="edge">
|
||||
<title>A14->A11</title>
|
||||
<path fill="none" stroke="#000000" d="M341.1152,-1185.9405C320.5475,-1057.7747 293.7865,-891.0162 274.7116,-772.1524"/>
|
||||
<polygon fill="none" stroke="#000000" points="337.6695,-1186.5583 342.7099,-1195.8774 344.5811,-1185.4491 337.6695,-1186.5583"/>
|
||||
<!-- A2 -->
|
||||
<g id="node3" class="node">
|
||||
<title>A2</title>
|
||||
<polygon fill="none" stroke="#000000" points="179.066,-662 179.066,-694 277.066,-694 277.066,-662 179.066,-662"/>
|
||||
<text text-anchor="start" x="204.4505" y="-675" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterG3</text>
|
||||
<polygon fill="none" stroke="#000000" points="179.066,-606 179.066,-662 277.066,-662 277.066,-606 179.066,-606"/>
|
||||
<text text-anchor="start" x="218.063" y="-643" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="188.619" y="-631" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote:StreamPtr</text>
|
||||
<text text-anchor="start" x="193.898" y="-619" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local:StreamPtr</text>
|
||||
<polygon fill="none" stroke="#000000" points="179.066,-550 179.066,-606 277.066,-606 277.066,-550 179.066,-550"/>
|
||||
<text text-anchor="start" x="192.508" y="-587" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">create_remote()</text>
|
||||
<text text-anchor="start" x="213.0685" y="-563" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A15->A14 -->
|
||||
<!-- A3 -->
|
||||
<g id="node4" class="node">
|
||||
<title>A3</title>
|
||||
<polygon fill="none" stroke="#000000" points="400.4026,-320 303.7294,-320 303.7294,-284 400.4026,-284 400.4026,-320"/>
|
||||
<text text-anchor="middle" x="352.066" y="-299" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local:StreamPtr</text>
|
||||
</g>
|
||||
<!-- A2->A3 -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>A2->A3</title>
|
||||
<path fill="none" stroke="#000000" d="M260.3657,-538.4062C268.7304,-516.7744 277.7293,-493.5168 286.066,-472 305.502,-421.8362 328.2143,-363.368 341.2906,-329.7205"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="260.2523,-538.6998 261.8194,-545.7386 255.9247,-549.8923 254.3577,-542.8536 260.2523,-538.6998"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="345.0251,-320.1117 345.5968,-331.0627 343.2138,-324.7721 341.4024,-329.4325 341.4024,-329.4325 341.4024,-329.4325 343.2138,-324.7721 337.2081,-327.8023 345.0251,-320.1117 345.0251,-320.1117"/>
|
||||
</g>
|
||||
<!-- A4 -->
|
||||
<g id="node5" class="node">
|
||||
<title>A4</title>
|
||||
<polygon fill="none" stroke="#000000" points="285.4601,-320 178.6719,-320 178.6719,-284 285.4601,-284 285.4601,-320"/>
|
||||
<text text-anchor="middle" x="232.066" y="-299" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote:StreamPtr</text>
|
||||
</g>
|
||||
<!-- A2->A4 -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>A2->A4</title>
|
||||
<path fill="none" stroke="#000000" d="M229.12,-537.6831C229.9778,-469.0527 231.1375,-376.283 231.7124,-330.2853"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="229.1188,-537.7877 233.0434,-543.8372 228.9687,-549.7868 225.044,-543.7372 229.1188,-537.7877"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="231.839,-320.1609 236.2135,-330.2164 231.7764,-325.1605 231.7139,-330.1601 231.7139,-330.1601 231.7139,-330.1601 231.7764,-325.1605 227.2143,-330.1038 231.839,-320.1609 231.839,-320.1609"/>
|
||||
</g>
|
||||
<!-- A8 -->
|
||||
<g id="node9" class="node">
|
||||
<title>A8</title>
|
||||
<polygon fill="none" stroke="#000000" points="246.066,-100 246.066,-132 424.066,-132 424.066,-100 246.066,-100"/>
|
||||
<text text-anchor="start" x="290.6175" y="-113" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStreamServer</text>
|
||||
<polygon fill="none" stroke="#000000" points="246.066,-68 246.066,-100 424.066,-100 424.066,-68 246.066,-68"/>
|
||||
<text text-anchor="start" x="302.837" y="-81" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">create_remote</text>
|
||||
<polygon fill="none" stroke="#000000" points="246.066,0 246.066,-68 424.066,-68 424.066,0 246.066,0"/>
|
||||
<text text-anchor="start" x="286.7235" y="-49" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>server_loop()</text>
|
||||
<text text-anchor="start" x="277.5545" y="-37" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>_async_forward()</text>
|
||||
<text text-anchor="start" x="255.875" y="-25" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>publish_outstanding_mqtt()</text>
|
||||
<text text-anchor="start" x="320.0685" y="-13" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A3->A8 -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>A3->A8</title>
|
||||
<path fill="none" stroke="#000000" d="M349.8809,-271.6651C347.5364,-239.1181 343.722,-186.1658 340.5509,-142.1431"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="349.898,-271.9044 354.3188,-277.6014 350.7603,-283.8733 346.3395,-278.1763 349.898,-271.9044"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="339.8226,-132.0321 345.0295,-141.6829 340.1818,-137.0192 340.5411,-142.0063 340.5411,-142.0063 340.5411,-142.0063 340.1818,-137.0192 336.0527,-142.3296 339.8226,-132.0321 339.8226,-132.0321"/>
|
||||
</g>
|
||||
<!-- A9 -->
|
||||
<g id="node10" class="node">
|
||||
<title>A9</title>
|
||||
<polygon fill="none" stroke="#000000" points="74.066,-82 74.066,-114 212.066,-114 212.066,-82 74.066,-82"/>
|
||||
<text text-anchor="start" x="100.563" y="-95" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStreamClient</text>
|
||||
<polygon fill="none" stroke="#000000" points="74.066,-62 74.066,-82 212.066,-82 212.066,-62 74.066,-62"/>
|
||||
<polygon fill="none" stroke="#000000" points="74.066,-18 74.066,-62 212.066,-62 212.066,-18 74.066,-18"/>
|
||||
<text text-anchor="start" x="96.944" y="-43" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>client_loop()</text>
|
||||
<text text-anchor="start" x="83.89" y="-31" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>_async_forward())</text>
|
||||
</g>
|
||||
<!-- A4->A9 -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>A4->A9</title>
|
||||
<path fill="none" stroke="#000000" d="M225.2301,-283.8733C212.4699,-250.0372 184.5329,-175.9573 164.7878,-123.5994"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="161.2018,-114.0904 168.941,-121.8593 162.9661,-118.7688 164.7305,-123.4472 164.7305,-123.4472 164.7305,-123.4472 162.9661,-118.7688 160.5199,-125.0351 161.2018,-114.0904 161.2018,-114.0904"/>
|
||||
<text text-anchor="middle" x="210.9254" y="-266.8956" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
|
||||
</g>
|
||||
<!-- A5 -->
|
||||
<g id="node6" class="node">
|
||||
<title>A5</title>
|
||||
<polygon fill="none" stroke="#000000" points="129.066,-1114 129.066,-1146 246.066,-1146 246.066,-1114 129.066,-1114"/>
|
||||
<text text-anchor="start" x="156.995" y="-1127" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><<AsyncIfc>></text>
|
||||
<polygon fill="none" stroke="#000000" points="129.066,-1094 129.066,-1114 246.066,-1114 246.066,-1094 129.066,-1094"/>
|
||||
<polygon fill="none" stroke="#000000" points="129.066,-822 129.066,-1094 246.066,-1094 246.066,-822 129.066,-822"/>
|
||||
<text text-anchor="start" x="157.002" y="-1075" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">set_node_id()</text>
|
||||
<text text-anchor="start" x="155.332" y="-1063" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">get_conn_no()</text>
|
||||
<text text-anchor="start" x="169.2295" y="-1039" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_add()</text>
|
||||
<text text-anchor="start" x="167.01" y="-1027" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_flush()</text>
|
||||
<text text-anchor="start" x="170.6195" y="-1015" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_get()</text>
|
||||
<text text-anchor="start" x="166.7295" y="-1003" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_peek()</text>
|
||||
<text text-anchor="start" x="170.8995" y="-991" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_log()</text>
|
||||
<text text-anchor="start" x="166.735" y="-979" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_clear()</text>
|
||||
<text text-anchor="start" x="170.8995" y="-967" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_len()</text>
|
||||
<text text-anchor="start" x="165.3405" y="-943" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_add()</text>
|
||||
<text text-anchor="start" x="167.0105" y="-931" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_log()</text>
|
||||
<text text-anchor="start" x="170.3445" y="-919" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_get()</text>
|
||||
<text text-anchor="start" x="166.4545" y="-907" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_peek()</text>
|
||||
<text text-anchor="start" x="170.6245" y="-895" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_log()</text>
|
||||
<text text-anchor="start" x="166.46" y="-883" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_clear()</text>
|
||||
<text text-anchor="start" x="170.6245" y="-871" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_len()</text>
|
||||
<text text-anchor="start" x="162.565" y="-859" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_set_cb()</text>
|
||||
<text text-anchor="start" x="138.9455" y="-835" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">prot_set_timeout_cb()</text>
|
||||
</g>
|
||||
<!-- A6 -->
|
||||
<g id="node7" class="node">
|
||||
<title>A6</title>
|
||||
<polygon fill="none" stroke="#000000" points="66.066,-652 66.066,-684 159.066,-684 159.066,-652 66.066,-652"/>
|
||||
<text text-anchor="start" x="84.23" y="-665" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncIfcImpl</text>
|
||||
<polygon fill="none" stroke="#000000" points="66.066,-560 66.066,-652 159.066,-652 159.066,-560 66.066,-560"/>
|
||||
<text text-anchor="start" x="75.614" y="-633" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_fifo:ByteFifo</text>
|
||||
<text text-anchor="start" x="79.503" y="-621" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_fifo:ByteFifo</text>
|
||||
<text text-anchor="start" x="79.228" y="-609" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_fifo:ByteFifo</text>
|
||||
<text text-anchor="start" x="78.662" y="-597" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">conn_no:Count</text>
|
||||
<text text-anchor="start" x="94.7795" y="-585" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">node_id</text>
|
||||
<text text-anchor="start" x="88.1155" y="-573" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">timeout_cb</text>
|
||||
</g>
|
||||
<!-- A5->A6 -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>A5->A6</title>
|
||||
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M151.3775,-811.7434C141.9017,-766.0069 132.2713,-719.5241 124.914,-684.013"/>
|
||||
<polygon fill="none" stroke="#000000" points="148.0039,-812.7126 153.4599,-821.7945 154.8583,-811.2924 148.0039,-812.7126"/>
|
||||
</g>
|
||||
<!-- A7 -->
|
||||
<g id="node8" class="node">
|
||||
<title>A7</title>
|
||||
<polygon fill="none" stroke="#000000" points="59.066,-390 59.066,-422 161.066,-422 161.066,-390 59.066,-390"/>
|
||||
<text text-anchor="start" x="80.34" y="-403" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStream</text>
|
||||
<polygon fill="none" stroke="#000000" points="59.066,-310 59.066,-390 161.066,-390 161.066,-310 59.066,-310"/>
|
||||
<text text-anchor="start" x="95.619" y="-371" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">reader</text>
|
||||
<text text-anchor="start" x="97.849" y="-359" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">writer</text>
|
||||
<text text-anchor="start" x="100.063" y="-347" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="95.619" y="-335" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">r_addr</text>
|
||||
<text text-anchor="start" x="96.174" y="-323" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">l_addr</text>
|
||||
<polygon fill="none" stroke="#000000" points="59.066,-182 59.066,-310 161.066,-310 161.066,-182 59.066,-182"/>
|
||||
<text text-anchor="start" x="81.72" y="-279" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>loop</text>
|
||||
<text text-anchor="start" x="97.848" y="-267" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">disc()</text>
|
||||
<text text-anchor="start" x="95.0685" y="-255" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
<text text-anchor="start" x="90.62" y="-243" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
|
||||
<text text-anchor="start" x="75.3365" y="-219" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_read()</text>
|
||||
<text text-anchor="start" x="74.787" y="-207" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_write()</text>
|
||||
<text text-anchor="start" x="68.673" y="-195" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_forward()</text>
|
||||
</g>
|
||||
<!-- A6->A7 -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>A6->A7</title>
|
||||
<path fill="none" stroke="#000000" d="M111.6134,-549.5774C111.3784,-511.9877 111.0852,-465.0771 110.8174,-422.2295"/>
|
||||
<polygon fill="none" stroke="#000000" points="108.1155,-549.9435 111.678,-559.9214 115.1153,-549.8996 108.1155,-549.9435"/>
|
||||
</g>
|
||||
<!-- A7->A8 -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>A7->A8</title>
|
||||
<path fill="none" stroke="#000000" d="M167.5272,-185.0204C168.3649,-184.0001 169.2111,-182.9929 170.066,-182 191.4283,-157.1889 219.1964,-135.0276 245.8416,-116.8901"/>
|
||||
<polygon fill="none" stroke="#000000" points="164.637,-183.0361 161.2751,-193.0834 170.1688,-187.3255 164.637,-183.0361"/>
|
||||
</g>
|
||||
<!-- A7->A9 -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>A7->A9</title>
|
||||
<path fill="none" stroke="#000000" d="M128.2709,-171.8077C131.1447,-151.2556 133.9487,-131.2022 136.3294,-114.1772"/>
|
||||
<polygon fill="none" stroke="#000000" points="124.7747,-171.5375 126.856,-181.9259 131.7072,-172.5069 124.7747,-171.5375"/>
|
||||
</g>
|
||||
<!-- A10 -->
|
||||
<g id="node11" class="node">
|
||||
<title>A10</title>
|
||||
<polygon fill="none" stroke="#000000" points="295.066,-740 295.066,-772 409.066,-772 409.066,-740 295.066,-740"/>
|
||||
<text text-anchor="start" x="338.174" y="-753" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Talent</text>
|
||||
<polygon fill="none" stroke="#000000" points="295.066,-600 295.066,-740 409.066,-740 409.066,-600 295.066,-600"/>
|
||||
<text text-anchor="start" x="332.889" y="-721" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">conn_no</text>
|
||||
<text text-anchor="start" x="342.063" y="-709" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="304.829" y="-685" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">await_conn_resp_cnt</text>
|
||||
<text text-anchor="start" x="339.8435" y="-673" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">id_str</text>
|
||||
<text text-anchor="start" x="320.666" y="-661" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">contact_name</text>
|
||||
<text text-anchor="start" x="324.006" y="-649" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">contact_mail</text>
|
||||
<text text-anchor="start" x="327.6105" y="-637" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">db:InfosG3</text>
|
||||
<text text-anchor="start" x="325.95" y="-625" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb:Modbus</text>
|
||||
<text text-anchor="start" x="338.178" y="-613" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">switch</text>
|
||||
<polygon fill="none" stroke="#000000" points="295.066,-472 295.066,-600 409.066,-600 409.066,-472 295.066,-472"/>
|
||||
<text text-anchor="start" x="309.5585" y="-581" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_contact_info()</text>
|
||||
<text text-anchor="start" x="311.4985" y="-569" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_ota_update()</text>
|
||||
<text text-anchor="start" x="317.3425" y="-557" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_get_time()</text>
|
||||
<text text-anchor="start" x="305.3945" y="-545" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_collector_data()</text>
|
||||
<text text-anchor="start" x="307.3395" y="-533" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_inverter_data()</text>
|
||||
<text text-anchor="start" x="316.5065" y="-521" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_unknown()</text>
|
||||
<text text-anchor="start" x="332.62" y="-497" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
|
||||
<text text-anchor="start" x="337.0685" y="-485" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A10->A3 -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>A10->A3</title>
|
||||
<path fill="none" stroke="#000000" d="M352.066,-461.6172C352.066,-412.1611 352.066,-362.7538 352.066,-332.2961"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="352.066,-471.8382 347.5661,-461.8382 352.066,-466.8382 352.0661,-461.8382 352.0661,-461.8382 352.0661,-461.8382 352.066,-466.8382 356.5661,-461.8383 352.066,-471.8382 352.066,-471.8382"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="352.0661,-332.0807 348.066,-326.0808 352.066,-320.0807 356.066,-326.0807 352.0661,-332.0807"/>
|
||||
</g>
|
||||
<!-- A10->A4 -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>A10->A4</title>
|
||||
<path fill="none" stroke="#000000" d="M292.1869,-462.3225C270.8082,-405.3126 249.4091,-348.2482 238.8463,-320.0807"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="295.7553,-471.8382 288.0306,-464.055 293.9997,-467.1566 292.244,-462.4749 292.244,-462.4749 292.244,-462.4749 293.9997,-467.1566 296.4575,-460.8948 295.7553,-471.8382 295.7553,-471.8382"/>
|
||||
<text text-anchor="middle" x="253.125" y="-331.0849" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
|
||||
</g>
|
||||
<!-- A12 -->
|
||||
<g id="node13" class="node">
|
||||
<title>A12</title>
|
||||
<polygon fill="none" stroke="#000000" points="432.066,-318 432.066,-350 499.066,-350 499.066,-318 432.066,-318"/>
|
||||
<text text-anchor="start" x="448.059" y="-331" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InfosG3</text>
|
||||
<polygon fill="none" stroke="#000000" points="432.066,-298 432.066,-318 499.066,-318 499.066,-298 432.066,-298"/>
|
||||
<polygon fill="none" stroke="#000000" points="432.066,-254 432.066,-298 499.066,-298 499.066,-254 432.066,-254"/>
|
||||
<text text-anchor="start" x="441.95" y="-279" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_confs()</text>
|
||||
<text text-anchor="start" x="449.734" y="-267" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">parse()</text>
|
||||
</g>
|
||||
<!-- A10->A12 -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>A10->A12</title>
|
||||
<path fill="none" stroke="#000000" d="M405.0919,-471.8382C419.1748,-431.9575 433.5466,-391.2585 444.6898,-359.7024"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="448.0405,-350.2137 448.9539,-361.1415 446.3756,-354.9284 444.7107,-359.6431 444.7107,-359.6431 444.7107,-359.6431 446.3756,-354.9284 440.4675,-358.1447 448.0405,-350.2137 448.0405,-350.2137"/>
|
||||
</g>
|
||||
<!-- A11 -->
|
||||
<g id="node12" class="node">
|
||||
<title>A11</title>
|
||||
<polygon fill="none" stroke="#000000" points="428.066,-710 428.066,-742 531.066,-742 531.066,-710 428.066,-710"/>
|
||||
<text text-anchor="start" x="468.728" y="-723" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Infos</text>
|
||||
<polygon fill="none" stroke="#000000" points="428.066,-654 428.066,-710 531.066,-710 531.066,-654 428.066,-654"/>
|
||||
<text text-anchor="start" x="471.5075" y="-691" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">stat</text>
|
||||
<text text-anchor="start" x="447.052" y="-679" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">new_stat_data</text>
|
||||
<text text-anchor="start" x="460.6695" y="-667" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">info_dev</text>
|
||||
<polygon fill="none" stroke="#000000" points="428.066,-502 428.066,-654 531.066,-654 531.066,-502 428.066,-502"/>
|
||||
<text text-anchor="start" x="455.4015" y="-635" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">static_init()</text>
|
||||
<text text-anchor="start" x="453.4505" y="-623" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dev_value()</text>
|
||||
<text text-anchor="start" x="450.3965" y="-611" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inc_counter()</text>
|
||||
<text text-anchor="start" x="448.7265" y="-599" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dec_counter()</text>
|
||||
<text text-anchor="start" x="446.776" y="-587" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_proxy_conf</text>
|
||||
<text text-anchor="start" x="461.779" y="-575" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_conf</text>
|
||||
<text text-anchor="start" x="454.56" y="-563" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_remove</text>
|
||||
<text text-anchor="start" x="455.9405" y="-551" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">update_db</text>
|
||||
<text text-anchor="start" x="440.103" y="-539" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">set_db_def_value</text>
|
||||
<text text-anchor="start" x="449.5515" y="-527" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">get_db_value</text>
|
||||
<text text-anchor="start" x="437.8885" y="-515" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ignore_this_device</text>
|
||||
</g>
|
||||
<!-- A11->A12 -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>A11->A12</title>
|
||||
<path fill="none" stroke="#000000" d="M473.3644,-491.6786C471.1803,-441.7544 468.8213,-387.8351 467.1788,-350.293"/>
|
||||
<polygon fill="none" stroke="#000000" points="469.8793,-492.0959 473.8131,-501.9334 476.8726,-491.7899 469.8793,-492.0959"/>
|
||||
</g>
|
||||
<!-- A13 -->
|
||||
<g id="node14" class="node">
|
||||
<title>A13</title>
|
||||
<polygon fill="none" stroke="#000000" points="156.066,-1524 156.066,-1556 305.066,-1556 305.066,-1524 156.066,-1524"/>
|
||||
<text text-anchor="start" x="210.2835" y="-1537" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Message</text>
|
||||
<polygon fill="none" stroke="#000000" points="156.066,-1300 156.066,-1524 305.066,-1524 305.066,-1300 156.066,-1300"/>
|
||||
<text text-anchor="start" x="193.8925" y="-1505" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">server_side:bool</text>
|
||||
<text text-anchor="start" x="204.45" y="-1493" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb:Modbus</text>
|
||||
<text text-anchor="start" x="205.2845" y="-1481" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ifc:AsyncIfc</text>
|
||||
<text text-anchor="start" x="212.7795" y="-1469" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">node_id</text>
|
||||
<text text-anchor="start" x="191.109" y="-1457" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">header_valid:bool</text>
|
||||
<text text-anchor="start" x="205.556" y="-1445" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">header_len</text>
|
||||
<text text-anchor="start" x="211.39" y="-1433" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">data_len</text>
|
||||
<text text-anchor="start" x="208.8905" y="-1421" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">unique_id</text>
|
||||
<text text-anchor="start" x="202.781" y="-1409" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sug_area:str</text>
|
||||
<text text-anchor="start" x="199.722" y="-1397" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">new_data:dict</text>
|
||||
<text text-anchor="start" x="206.666" y="-1385" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">state:State</text>
|
||||
<text text-anchor="start" x="180.2705" y="-1373" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">shutdown_started:bool</text>
|
||||
<text text-anchor="start" x="199.4505" y="-1361" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">modbus_elms</text>
|
||||
<text text-anchor="start" x="195.573" y="-1349" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb_timer:Timer</text>
|
||||
<text text-anchor="start" x="204.451" y="-1337" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb_timeout</text>
|
||||
<text text-anchor="start" x="193.6185" y="-1325" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb_first_timeout</text>
|
||||
<text text-anchor="start" x="184.72" y="-1313" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">modbus_polling:bool</text>
|
||||
<polygon fill="none" stroke="#000000" points="156.066,-1196 156.066,-1300 305.066,-1300 305.066,-1196 156.066,-1196"/>
|
||||
<text text-anchor="start" x="179.4505" y="-1281" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_set_mqtt_timestamp()</text>
|
||||
<text text-anchor="start" x="208.066" y="-1269" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_timeout()</text>
|
||||
<text text-anchor="start" x="180.8335" y="-1257" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_send_modbus_cmd()</text>
|
||||
<text text-anchor="start" x="165.8255" y="-1245" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async> end_modbus_cmd()</text>
|
||||
<text text-anchor="start" x="215.5685" y="-1233" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
<text text-anchor="start" x="201.3965" y="-1221" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inc_counter()</text>
|
||||
<text text-anchor="start" x="199.7265" y="-1209" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dec_counter()</text>
|
||||
</g>
|
||||
<!-- A13->A5 -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>A13->A5</title>
|
||||
<path fill="none" stroke="#000000" d="M210.2965,-1195.7758C208.8462,-1182.5547 207.3854,-1169.2373 205.9406,-1156.0662"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="204.8393,-1146.0268 210.403,-1155.4764 205.3846,-1150.997 205.9298,-1155.9672 205.9298,-1155.9672 205.9298,-1155.9672 205.3846,-1150.997 201.4567,-1156.4579 204.8393,-1146.0268 204.8393,-1146.0268"/>
|
||||
<text text-anchor="middle" x="199.9181" y="-1175.6794" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">use</text>
|
||||
</g>
|
||||
<!-- A13->A10 -->
|
||||
<g id="edge16" class="edge">
|
||||
<title>A15->A14</title>
|
||||
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M329.7896,-1673.8004C334.3532,-1641.3079 340.3126,-1598.8764 346.2965,-1556.2713"/>
|
||||
<polygon fill="none" stroke="#000000" points="326.2837,-1673.5986 328.3587,-1683.9883 333.2156,-1674.5723 326.2837,-1673.5986"/>
|
||||
<title>A13->A10</title>
|
||||
<path fill="none" stroke="#000000" d="M260.8183,-1185.9405C281.556,-1057.7747 308.5382,-891.0162 327.7708,-772.1524"/>
|
||||
<polygon fill="none" stroke="#000000" points="257.3528,-1185.4467 259.2105,-1195.8774 264.2629,-1186.5648 257.3528,-1185.4467"/>
|
||||
</g>
|
||||
<!-- A16 -->
|
||||
<g id="node17" class="node">
|
||||
<title>A16</title>
|
||||
<polygon fill="none" stroke="#000000" points="385.6155,-1826 385.6155,-1858 460.6155,-1858 460.6155,-1826 385.6155,-1826"/>
|
||||
<text text-anchor="start" x="405.333" y="-1839" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Modbus</text>
|
||||
<polygon fill="none" stroke="#000000" points="385.6155,-1674 385.6155,-1826 460.6155,-1826 460.6155,-1674 385.6155,-1674"/>
|
||||
<text text-anchor="start" x="414.777" y="-1807" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">que</text>
|
||||
<text text-anchor="start" x="395.6055" y="-1783" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">snd_handler</text>
|
||||
<text text-anchor="start" x="396.7205" y="-1771" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rsp_handler</text>
|
||||
<text text-anchor="start" x="406.724" y="-1759" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">timeout</text>
|
||||
<text text-anchor="start" x="397.005" y="-1747" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">max_retires</text>
|
||||
<text text-anchor="start" x="405.0575" y="-1735" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">last_xxx</text>
|
||||
<text text-anchor="start" x="417.007" y="-1723" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">err</text>
|
||||
<text text-anchor="start" x="403.669" y="-1711" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">retry_cnt</text>
|
||||
<text text-anchor="start" x="401.9945" y="-1699" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">req_pend</text>
|
||||
<text text-anchor="start" x="416.452" y="-1687" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tim</text>
|
||||
<polygon fill="none" stroke="#000000" points="385.6155,-1606 385.6155,-1674 460.6155,-1674 460.6155,-1606 385.6155,-1606"/>
|
||||
<text text-anchor="start" x="397.0055" y="-1655" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">build_msg()</text>
|
||||
<text text-anchor="start" x="400.3395" y="-1643" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">recv_req()</text>
|
||||
<text text-anchor="start" x="397.8395" y="-1631" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">recv_resp()</text>
|
||||
<text text-anchor="start" x="408.118" y="-1619" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
<!-- A14->A13 -->
|
||||
<g id="edge15" class="edge">
|
||||
<title>A14->A13</title>
|
||||
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M188.2401,-1673.8004C192.8037,-1641.3079 198.7631,-1598.8764 204.747,-1556.2713"/>
|
||||
<polygon fill="none" stroke="#000000" points="184.7342,-1673.5986 186.8092,-1683.9883 191.6661,-1674.5723 184.7342,-1673.5986"/>
|
||||
</g>
|
||||
<!-- A16->A14 -->
|
||||
<g id="edge18" class="edge">
|
||||
<title>A16->A14</title>
|
||||
<path fill="none" stroke="#000000" d="M403.1382,-1596.041C401.2623,-1582.9463 399.3403,-1569.5297 397.4159,-1556.0971"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="404.563,-1605.9867 398.6903,-1596.726 403.8539,-1601.0373 403.1448,-1596.0878 403.1448,-1596.0878 403.1448,-1596.0878 403.8539,-1601.0373 407.5994,-1595.4496 404.563,-1605.9867 404.563,-1605.9867"/>
|
||||
<text text-anchor="middle" x="408.3534" y="-1569.8414" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">has</text>
|
||||
<text text-anchor="middle" x="393.6256" y="-1586.2424" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
|
||||
<!-- A15 -->
|
||||
<g id="node16" class="node">
|
||||
<title>A15</title>
|
||||
<polygon fill="none" stroke="#000000" points="244.066,-1826 244.066,-1858 319.066,-1858 319.066,-1826 244.066,-1826"/>
|
||||
<text text-anchor="start" x="263.7835" y="-1839" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Modbus</text>
|
||||
<polygon fill="none" stroke="#000000" points="244.066,-1674 244.066,-1826 319.066,-1826 319.066,-1674 244.066,-1674"/>
|
||||
<text text-anchor="start" x="273.2275" y="-1807" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">que</text>
|
||||
<text text-anchor="start" x="254.056" y="-1783" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">snd_handler</text>
|
||||
<text text-anchor="start" x="255.171" y="-1771" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rsp_handler</text>
|
||||
<text text-anchor="start" x="265.1745" y="-1759" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">timeout</text>
|
||||
<text text-anchor="start" x="255.4555" y="-1747" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">max_retires</text>
|
||||
<text text-anchor="start" x="263.508" y="-1735" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">last_xxx</text>
|
||||
<text text-anchor="start" x="275.4575" y="-1723" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">err</text>
|
||||
<text text-anchor="start" x="262.1195" y="-1711" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">retry_cnt</text>
|
||||
<text text-anchor="start" x="260.445" y="-1699" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">req_pend</text>
|
||||
<text text-anchor="start" x="274.9025" y="-1687" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tim</text>
|
||||
<polygon fill="none" stroke="#000000" points="244.066,-1606 244.066,-1674 319.066,-1674 319.066,-1606 244.066,-1606"/>
|
||||
<text text-anchor="start" x="255.456" y="-1655" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">build_msg()</text>
|
||||
<text text-anchor="start" x="258.79" y="-1643" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">recv_req()</text>
|
||||
<text text-anchor="start" x="256.29" y="-1631" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">recv_resp()</text>
|
||||
<text text-anchor="start" x="266.5685" y="-1619" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A15->A13 -->
|
||||
<g id="edge17" class="edge">
|
||||
<title>A15->A13</title>
|
||||
<path fill="none" stroke="#000000" d="M261.5887,-1596.041C259.7128,-1582.9463 257.7908,-1569.5297 255.8664,-1556.0971"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="263.0135,-1605.9867 257.1408,-1596.726 262.3044,-1601.0373 261.5953,-1596.0878 261.5953,-1596.0878 261.5953,-1596.0878 262.3044,-1601.0373 266.0499,-1595.4496 263.0135,-1605.9867 263.0135,-1605.9867"/>
|
||||
<text text-anchor="middle" x="266.8039" y="-1569.8414" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">has</text>
|
||||
<text text-anchor="middle" x="252.0761" y="-1586.2424" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 33 KiB |
@@ -5,10 +5,10 @@
|
||||
[note: Example of instantiation for a GEN3 inverter!{bg:cornsilk}]
|
||||
[<<AbstractIterMeta>>||__iter__()]
|
||||
|
||||
[InverterBase|addr;remote:StreamPtr;local:StreamPtr|create_remote();;close()]
|
||||
[InverterBase]^[InverterG3]
|
||||
[InverterBase]++->[local:StreamPtr]
|
||||
[InverterBase]++->[remote:StreamPtr]
|
||||
[InverterG3|addr;remote:StreamPtr;local:StreamPtr|create_remote();;close()]
|
||||
[InverterG3]++->[local:StreamPtr]
|
||||
[InverterG3]++->[remote:StreamPtr]
|
||||
|
||||
[<<AsyncIfc>>||set_node_id();get_conn_no();;tx_add();tx_flush();tx_get();tx_peek();tx_log();tx_clear();tx_len();;fwd_add();fwd_log();rx_get();rx_peek();rx_log();rx_clear();rx_len();rx_set_cb();;prot_set_timeout_cb()]
|
||||
[AsyncIfcImpl|fwd_fifo:ByteFifo;tx_fifo:ByteFifo;rx_fifo:ByteFifo;conn_no:Count;node_id;timeout_cb]
|
||||
[AsyncStream|reader;writer;addr;r_addr;l_addr|;<async>loop;disc();close();healthy();;__async_read();__async_write();__async_forward()]
|
||||
|
||||
@@ -4,379 +4,364 @@
|
||||
<!-- Generated by graphviz version 2.40.1 (20161225.0304)
|
||||
-->
|
||||
<!-- Title: G Pages: 1 -->
|
||||
<svg width="597pt" height="1940pt"
|
||||
viewBox="0.00 0.00 597.00 1940.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<svg width="541pt" height="1940pt"
|
||||
viewBox="0.00 0.00 540.62 1940.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 1936)">
|
||||
<title>G</title>
|
||||
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-1936 593,-1936 593,4 -4,4"/>
|
||||
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-1936 536.6165,-1936 536.6165,4 -4,4"/>
|
||||
<!-- A0 -->
|
||||
<g id="node1" class="node">
|
||||
<title>A0</title>
|
||||
<polygon fill="#fff8dc" stroke="#000000" points="287.2332,-1912 172.7668,-1912 172.7668,-1868 293.2332,-1868 293.2332,-1906 287.2332,-1912"/>
|
||||
<polyline fill="none" stroke="#000000" points="287.2332,-1912 287.2332,-1906 "/>
|
||||
<polyline fill="none" stroke="#000000" points="293.2332,-1906 287.2332,-1906 "/>
|
||||
<text text-anchor="middle" x="233" y="-1899" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Example of</text>
|
||||
<text text-anchor="middle" x="233" y="-1887" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">instantiation for a</text>
|
||||
<text text-anchor="middle" x="233" y="-1875" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">GEN3PLUS inverter!</text>
|
||||
<polygon fill="#fff8dc" stroke="#000000" points="114.3497,-1912 -.1167,-1912 -.1167,-1868 120.3497,-1868 120.3497,-1906 114.3497,-1912"/>
|
||||
<polyline fill="none" stroke="#000000" points="114.3497,-1912 114.3497,-1906 "/>
|
||||
<polyline fill="none" stroke="#000000" points="120.3497,-1906 114.3497,-1906 "/>
|
||||
<text text-anchor="middle" x="60.1165" y="-1899" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Example of</text>
|
||||
<text text-anchor="middle" x="60.1165" y="-1887" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">instantiation for a</text>
|
||||
<text text-anchor="middle" x="60.1165" y="-1875" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">GEN3PLUS inverter!</text>
|
||||
</g>
|
||||
<!-- A1 -->
|
||||
<g id="node2" class="node">
|
||||
<title>A1</title>
|
||||
<polygon fill="none" stroke="#000000" points="311,-1900 311,-1932 427,-1932 427,-1900 311,-1900"/>
|
||||
<text text-anchor="start" x="320.649" y="-1913" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><<AbstractIterMeta>></text>
|
||||
<polygon fill="none" stroke="#000000" points="311,-1880 311,-1900 427,-1900 427,-1880 311,-1880"/>
|
||||
<polygon fill="none" stroke="#000000" points="311,-1848 311,-1880 427,-1880 427,-1848 311,-1848"/>
|
||||
<text text-anchor="start" x="347.61" y="-1861" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__iter__()</text>
|
||||
</g>
|
||||
<!-- A15 -->
|
||||
<g id="node16" class="node">
|
||||
<title>A15</title>
|
||||
<polygon fill="none" stroke="#000000" points="324,-1688 324,-1720 414,-1720 414,-1688 324,-1688"/>
|
||||
<text text-anchor="start" x="333.7065" y="-1701" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><<ProtocolIfc>></text>
|
||||
<polygon fill="none" stroke="#000000" points="324,-1656 324,-1688 414,-1688 414,-1656 324,-1656"/>
|
||||
<text text-anchor="start" x="349.8335" y="-1669" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_registry</text>
|
||||
<polygon fill="none" stroke="#000000" points="324,-1624 324,-1656 414,-1656 414,-1624 324,-1624"/>
|
||||
<text text-anchor="start" x="354.0025" y="-1637" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A1->A15 -->
|
||||
<g id="edge15" class="edge">
|
||||
<title>A1->A15</title>
|
||||
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M369,-1837.756C369,-1802.0883 369,-1755.1755 369,-1720.3644"/>
|
||||
<polygon fill="none" stroke="#000000" points="365.5001,-1837.9674 369,-1847.9674 372.5001,-1837.9674 365.5001,-1837.9674"/>
|
||||
</g>
|
||||
<!-- A2 -->
|
||||
<g id="node3" class="node">
|
||||
<title>A2</title>
|
||||
<polygon fill="none" stroke="#000000" points="128,-632 128,-664 226,-664 226,-632 128,-632"/>
|
||||
<text text-anchor="start" x="148.66" y="-645" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterBase</text>
|
||||
<polygon fill="none" stroke="#000000" points="128,-576 128,-632 226,-632 226,-576 128,-576"/>
|
||||
<text text-anchor="start" x="166.997" y="-613" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="137.553" y="-601" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote:StreamPtr</text>
|
||||
<text text-anchor="start" x="142.832" y="-589" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local:StreamPtr</text>
|
||||
<polygon fill="none" stroke="#000000" points="128,-520 128,-576 226,-576 226,-520 128,-520"/>
|
||||
<text text-anchor="start" x="141.442" y="-557" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">create_remote()</text>
|
||||
<text text-anchor="start" x="162.0025" y="-533" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A3 -->
|
||||
<g id="node4" class="node">
|
||||
<title>A3</title>
|
||||
<polygon fill="none" stroke="#000000" points="0,-302 0,-334 116,-334 116,-302 0,-302"/>
|
||||
<text text-anchor="start" x="31.05" y="-315" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterG3P</text>
|
||||
<polygon fill="none" stroke="#000000" points="0,-270 0,-302 116,-302 116,-270 0,-270"/>
|
||||
<text text-anchor="start" x="9.6585" y="-283" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">forward_at_cmd_resp</text>
|
||||
</g>
|
||||
<!-- A2->A3 -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>A2->A3</title>
|
||||
<path fill="none" stroke="#000000" d="M143.4931,-510.3444C119.4997,-451.8732 88.4875,-376.2972 71.177,-334.1121"/>
|
||||
<polygon fill="none" stroke="#000000" points="140.3971,-512.0193 147.4314,-519.942 146.873,-509.3619 140.3971,-512.0193"/>
|
||||
</g>
|
||||
<!-- A4 -->
|
||||
<g id="node5" class="node">
|
||||
<title>A4</title>
|
||||
<polygon fill="none" stroke="#000000" points="230.3366,-320 133.6634,-320 133.6634,-284 230.3366,-284 230.3366,-320"/>
|
||||
<text text-anchor="middle" x="182" y="-299" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local:StreamPtr</text>
|
||||
</g>
|
||||
<!-- A2->A4 -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>A2->A4</title>
|
||||
<path fill="none" stroke="#000000" d="M178.4553,-507.5905C179.4883,-447.68 180.8113,-370.9429 181.5127,-330.266"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="178.4493,-507.9438 182.3453,-514.0119 178.2424,-519.942 174.3465,-513.8739 178.4493,-507.9438"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="181.6851,-320.2627 186.012,-330.3388 181.5989,-325.2619 181.5126,-330.2612 181.5126,-330.2612 181.5126,-330.2612 181.5989,-325.2619 177.0133,-330.1836 181.6851,-320.2627 181.6851,-320.2627"/>
|
||||
</g>
|
||||
<!-- A5 -->
|
||||
<g id="node6" class="node">
|
||||
<title>A5</title>
|
||||
<polygon fill="none" stroke="#000000" points="355.3941,-320 248.6059,-320 248.6059,-284 355.3941,-284 355.3941,-320"/>
|
||||
<text text-anchor="middle" x="302" y="-299" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote:StreamPtr</text>
|
||||
</g>
|
||||
<!-- A2->A5 -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>A2->A5</title>
|
||||
<path fill="none" stroke="#000000" d="M212.8581,-508.8093C238.9076,-448.3743 272.5536,-370.3156 290.1233,-329.5539"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="212.8095,-508.9221 214.1078,-516.0154 208.0595,-519.942 206.7612,-512.8487 212.8095,-508.9221"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="294.1282,-320.2627 294.3023,-331.2272 292.149,-324.8543 290.1698,-329.4459 290.1698,-329.4459 290.1698,-329.4459 292.149,-324.8543 286.0373,-327.6647 294.1282,-320.2627 294.1282,-320.2627"/>
|
||||
</g>
|
||||
<!-- A9 -->
|
||||
<g id="node10" class="node">
|
||||
<title>A9</title>
|
||||
<polygon fill="none" stroke="#000000" points="183,-100 183,-132 361,-132 361,-100 183,-100"/>
|
||||
<text text-anchor="start" x="227.5515" y="-113" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStreamServer</text>
|
||||
<polygon fill="none" stroke="#000000" points="183,-68 183,-100 361,-100 361,-68 183,-68"/>
|
||||
<text text-anchor="start" x="239.771" y="-81" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">create_remote</text>
|
||||
<polygon fill="none" stroke="#000000" points="183,0 183,-68 361,-68 361,0 183,0"/>
|
||||
<text text-anchor="start" x="223.6575" y="-49" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>server_loop()</text>
|
||||
<text text-anchor="start" x="214.4885" y="-37" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>_async_forward()</text>
|
||||
<text text-anchor="start" x="192.809" y="-25" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>publish_outstanding_mqtt()</text>
|
||||
<text text-anchor="start" x="257.0025" y="-13" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A4->A9 -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>A4->A9</title>
|
||||
<path fill="none" stroke="#000000" d="M193.2169,-272.5869C205.6662,-239.9419 226.2449,-185.9801 243.2484,-141.3932"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="193.1887,-272.661 194.7881,-279.6925 188.9127,-283.8733 187.3132,-276.8418 193.1887,-272.661"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="246.8183,-132.0321 247.4596,-142.9792 245.0366,-136.7039 243.2549,-141.3757 243.2549,-141.3757 243.2549,-141.3757 245.0366,-136.7039 239.0503,-139.7723 246.8183,-132.0321 246.8183,-132.0321"/>
|
||||
</g>
|
||||
<!-- A10 -->
|
||||
<g id="node11" class="node">
|
||||
<title>A10</title>
|
||||
<polygon fill="none" stroke="#000000" points="424,-82 424,-114 562,-114 562,-82 424,-82"/>
|
||||
<text text-anchor="start" x="450.497" y="-95" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStreamClient</text>
|
||||
<polygon fill="none" stroke="#000000" points="424,-62 424,-82 562,-82 562,-62 424,-62"/>
|
||||
<polygon fill="none" stroke="#000000" points="424,-18 424,-62 562,-62 562,-18 424,-18"/>
|
||||
<text text-anchor="start" x="446.878" y="-43" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>client_loop()</text>
|
||||
<text text-anchor="start" x="433.824" y="-31" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>_async_forward())</text>
|
||||
</g>
|
||||
<!-- A5->A10 -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>A5->A10</title>
|
||||
<path fill="none" stroke="#000000" d="M308.989,-283.7374C318.9281,-259.1334 338.7724,-214.6635 364,-182 380.8963,-160.1235 402.2571,-139.0239 422.71,-120.9559"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="430.4931,-114.1842 425.9026,-124.143 426.721,-117.4662 422.9488,-120.7481 422.9488,-120.7481 422.9488,-120.7481 426.721,-117.4662 419.9951,-117.3532 430.4931,-114.1842 430.4931,-114.1842"/>
|
||||
<text text-anchor="middle" x="308.0806" y="-260.758" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
|
||||
</g>
|
||||
<!-- A6 -->
|
||||
<g id="node7" class="node">
|
||||
<title>A6</title>
|
||||
<polygon fill="none" stroke="#000000" points="443,-1054 443,-1086 560,-1086 560,-1054 443,-1054"/>
|
||||
<text text-anchor="start" x="470.929" y="-1067" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><<AsyncIfc>></text>
|
||||
<polygon fill="none" stroke="#000000" points="443,-1034 443,-1054 560,-1054 560,-1034 443,-1034"/>
|
||||
<polygon fill="none" stroke="#000000" points="443,-762 443,-1034 560,-1034 560,-762 443,-762"/>
|
||||
<text text-anchor="start" x="470.936" y="-1015" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">set_node_id()</text>
|
||||
<text text-anchor="start" x="469.266" y="-1003" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">get_conn_no()</text>
|
||||
<text text-anchor="start" x="483.1635" y="-979" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_add()</text>
|
||||
<text text-anchor="start" x="480.944" y="-967" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_flush()</text>
|
||||
<text text-anchor="start" x="484.5535" y="-955" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_get()</text>
|
||||
<text text-anchor="start" x="480.6635" y="-943" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_peek()</text>
|
||||
<text text-anchor="start" x="484.8335" y="-931" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_log()</text>
|
||||
<text text-anchor="start" x="480.669" y="-919" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_clear()</text>
|
||||
<text text-anchor="start" x="484.8335" y="-907" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_len()</text>
|
||||
<text text-anchor="start" x="479.2745" y="-883" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_add()</text>
|
||||
<text text-anchor="start" x="480.9445" y="-871" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_log()</text>
|
||||
<text text-anchor="start" x="484.2785" y="-859" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_get()</text>
|
||||
<text text-anchor="start" x="480.3885" y="-847" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_peek()</text>
|
||||
<text text-anchor="start" x="484.5585" y="-835" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_log()</text>
|
||||
<text text-anchor="start" x="480.394" y="-823" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_clear()</text>
|
||||
<text text-anchor="start" x="484.5585" y="-811" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_len()</text>
|
||||
<text text-anchor="start" x="476.499" y="-799" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_set_cb()</text>
|
||||
<text text-anchor="start" x="452.8795" y="-775" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">prot_set_timeout_cb()</text>
|
||||
</g>
|
||||
<!-- A7 -->
|
||||
<g id="node8" class="node">
|
||||
<title>A7</title>
|
||||
<polygon fill="none" stroke="#000000" points="494,-622 494,-654 587,-654 587,-622 494,-622"/>
|
||||
<text text-anchor="start" x="512.164" y="-635" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncIfcImpl</text>
|
||||
<polygon fill="none" stroke="#000000" points="494,-530 494,-622 587,-622 587,-530 494,-530"/>
|
||||
<text text-anchor="start" x="503.548" y="-603" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_fifo:ByteFifo</text>
|
||||
<text text-anchor="start" x="507.437" y="-591" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_fifo:ByteFifo</text>
|
||||
<text text-anchor="start" x="507.162" y="-579" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_fifo:ByteFifo</text>
|
||||
<text text-anchor="start" x="506.596" y="-567" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">conn_no:Count</text>
|
||||
<text text-anchor="start" x="522.7135" y="-555" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">node_id</text>
|
||||
<text text-anchor="start" x="516.0495" y="-543" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">timeout_cb</text>
|
||||
</g>
|
||||
<!-- A6->A7 -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>A6->A7</title>
|
||||
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M521.2574,-751.5524C525.3561,-716.6607 529.4102,-682.1494 532.6937,-654.1971"/>
|
||||
<polygon fill="none" stroke="#000000" points="517.7337,-751.5502 520.043,-761.8903 524.6859,-752.367 517.7337,-751.5502"/>
|
||||
</g>
|
||||
<!-- A8 -->
|
||||
<g id="node9" class="node">
|
||||
<title>A8</title>
|
||||
<polygon fill="none" stroke="#000000" points="487,-390 487,-422 589,-422 589,-390 487,-390"/>
|
||||
<text text-anchor="start" x="508.274" y="-403" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStream</text>
|
||||
<polygon fill="none" stroke="#000000" points="487,-310 487,-390 589,-390 589,-310 487,-310"/>
|
||||
<text text-anchor="start" x="523.553" y="-371" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">reader</text>
|
||||
<text text-anchor="start" x="525.783" y="-359" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">writer</text>
|
||||
<text text-anchor="start" x="527.997" y="-347" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="523.553" y="-335" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">r_addr</text>
|
||||
<text text-anchor="start" x="524.108" y="-323" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">l_addr</text>
|
||||
<polygon fill="none" stroke="#000000" points="487,-182 487,-310 589,-310 589,-182 487,-182"/>
|
||||
<text text-anchor="start" x="509.654" y="-279" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>loop</text>
|
||||
<text text-anchor="start" x="525.782" y="-267" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">disc()</text>
|
||||
<text text-anchor="start" x="523.0025" y="-255" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
<text text-anchor="start" x="518.554" y="-243" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
|
||||
<text text-anchor="start" x="503.2705" y="-219" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_read()</text>
|
||||
<text text-anchor="start" x="502.721" y="-207" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_write()</text>
|
||||
<text text-anchor="start" x="496.607" y="-195" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_forward()</text>
|
||||
</g>
|
||||
<!-- A7->A8 -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>A7->A8</title>
|
||||
<path fill="none" stroke="#000000" d="M539.5006,-519.5861C539.2971,-490.0737 539.0562,-455.1552 538.8278,-422.0295"/>
|
||||
<polygon fill="none" stroke="#000000" points="536.002,-519.8121 539.5709,-529.7877 543.0018,-519.7638 536.002,-519.8121"/>
|
||||
</g>
|
||||
<!-- A8->A9 -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>A8->A9</title>
|
||||
<path fill="none" stroke="#000000" d="M480.5271,-185.826C479.3695,-184.5245 478.1938,-183.2483 477,-182 444.7093,-148.2346 400.4099,-121.5033 361.252,-102.2528"/>
|
||||
<polygon fill="none" stroke="#000000" points="477.867,-188.1011 486.9604,-193.5382 483.2424,-183.6171 477.867,-188.1011"/>
|
||||
</g>
|
||||
<!-- A8->A10 -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>A8->A10</title>
|
||||
<path fill="none" stroke="#000000" d="M513.2286,-172.088C509.2911,-151.438 505.4474,-131.2796 502.1863,-114.1772"/>
|
||||
<polygon fill="none" stroke="#000000" points="509.7933,-172.7584 515.1045,-181.9259 516.6695,-171.4473 509.7933,-172.7584"/>
|
||||
</g>
|
||||
<!-- A11 -->
|
||||
<g id="node12" class="node">
|
||||
<title>A11</title>
|
||||
<polygon fill="none" stroke="#000000" points="244,-668 244,-700 354,-700 354,-668 244,-668"/>
|
||||
<text text-anchor="start" x="271.495" y="-681" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">SolarmanV5</text>
|
||||
<polygon fill="none" stroke="#000000" points="244,-552 244,-668 354,-668 354,-552 244,-552"/>
|
||||
<text text-anchor="start" x="279.823" y="-649" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">conn_no</text>
|
||||
<text text-anchor="start" x="288.997" y="-637" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="253.994" y="-625" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inverter:InverterG3P</text>
|
||||
<text text-anchor="start" x="283.998" y="-613" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">control</text>
|
||||
<text text-anchor="start" x="287.0575" y="-601" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">serial</text>
|
||||
<text text-anchor="start" x="292.056" y="-589" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">snr</text>
|
||||
<text text-anchor="start" x="271.21" y="-577" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">db:InfosG3P</text>
|
||||
<text text-anchor="start" x="285.112" y="-565" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">switch</text>
|
||||
<polygon fill="none" stroke="#000000" points="244,-484 244,-552 354,-552 354,-484 244,-484"/>
|
||||
<text text-anchor="start" x="263.4405" y="-533" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_unknown()</text>
|
||||
<text text-anchor="start" x="279.554" y="-509" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
|
||||
<text text-anchor="start" x="284.0025" y="-497" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A11->A4 -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>A11->A4</title>
|
||||
<path fill="none" stroke="#000000" d="M251.4932,-474.2481C230.4181,-422.0107 207.3684,-364.879 193.8227,-331.3042"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="255.2671,-483.6023 247.3524,-476.0123 253.3964,-478.9655 251.5256,-474.3286 251.5256,-474.3286 251.5256,-474.3286 253.3964,-478.9655 255.6988,-472.6449 255.2671,-483.6023 255.2671,-483.6023"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="193.7733,-331.1815 187.8189,-327.1139 189.2835,-320.053 195.2379,-324.1207 193.7733,-331.1815"/>
|
||||
</g>
|
||||
<!-- A11->A5 -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>A11->A5</title>
|
||||
<path fill="none" stroke="#000000" d="M300.2256,-473.5237C300.8304,-415.0627 301.4968,-350.6465 301.8132,-320.053"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="300.1214,-483.6023 295.7251,-473.5562 300.1731,-478.6026 300.2249,-473.6028 300.2249,-473.6028 300.2249,-473.6028 300.1731,-478.6026 304.7247,-473.6494 300.1214,-483.6023 300.1214,-483.6023"/>
|
||||
<text text-anchor="middle" x="310.0777" y="-335.2657" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
|
||||
</g>
|
||||
<!-- A13 -->
|
||||
<g id="node14" class="node">
|
||||
<title>A13</title>
|
||||
<polygon fill="none" stroke="#000000" points="374,-336 374,-368 469,-368 469,-336 374,-336"/>
|
||||
<text text-anchor="start" x="400.6585" y="-349" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InfosG3P</text>
|
||||
<polygon fill="none" stroke="#000000" points="374,-304 374,-336 469,-336 469,-304 374,-304"/>
|
||||
<text text-anchor="start" x="383.7125" y="-317" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">client_mode:bool</text>
|
||||
<polygon fill="none" stroke="#000000" points="374,-236 374,-304 469,-304 469,-236 374,-236"/>
|
||||
<text text-anchor="start" x="397.884" y="-285" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_confs()</text>
|
||||
<text text-anchor="start" x="405.668" y="-273" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">parse()</text>
|
||||
<text text-anchor="start" x="409.282" y="-261" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">calc()</text>
|
||||
<text text-anchor="start" x="407.6135" y="-249" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">build()</text>
|
||||
</g>
|
||||
<!-- A11->A13 -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>A11->A13</title>
|
||||
<path fill="none" stroke="#000000" d="M344.6018,-483.6023C359.4473,-448.3138 375.5948,-409.9305 389.2039,-377.5809"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="393.1562,-368.1861 393.4263,-379.1487 391.2173,-372.7949 389.2784,-377.4036 389.2784,-377.4036 389.2784,-377.4036 391.2173,-372.7949 385.1305,-375.6586 393.1562,-368.1861 393.1562,-368.1861"/>
|
||||
</g>
|
||||
<!-- A12 -->
|
||||
<g id="node13" class="node">
|
||||
<title>A12</title>
|
||||
<polygon fill="none" stroke="#000000" points="373,-680 373,-712 476,-712 476,-680 373,-680"/>
|
||||
<text text-anchor="start" x="413.662" y="-693" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Infos</text>
|
||||
<polygon fill="none" stroke="#000000" points="373,-624 373,-680 476,-680 476,-624 373,-624"/>
|
||||
<text text-anchor="start" x="416.4415" y="-661" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">stat</text>
|
||||
<text text-anchor="start" x="391.986" y="-649" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">new_stat_data</text>
|
||||
<text text-anchor="start" x="405.6035" y="-637" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">info_dev</text>
|
||||
<polygon fill="none" stroke="#000000" points="373,-472 373,-624 476,-624 476,-472 373,-472"/>
|
||||
<text text-anchor="start" x="400.3355" y="-605" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">static_init()</text>
|
||||
<text text-anchor="start" x="398.3845" y="-593" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dev_value()</text>
|
||||
<text text-anchor="start" x="395.3305" y="-581" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inc_counter()</text>
|
||||
<text text-anchor="start" x="393.6605" y="-569" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dec_counter()</text>
|
||||
<text text-anchor="start" x="391.71" y="-557" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_proxy_conf</text>
|
||||
<text text-anchor="start" x="406.713" y="-545" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_conf</text>
|
||||
<text text-anchor="start" x="399.494" y="-533" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_remove</text>
|
||||
<text text-anchor="start" x="400.8745" y="-521" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">update_db</text>
|
||||
<text text-anchor="start" x="385.037" y="-509" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">set_db_def_value</text>
|
||||
<text text-anchor="start" x="394.4855" y="-497" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">get_db_value</text>
|
||||
<text text-anchor="start" x="382.8225" y="-485" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ignore_this_device</text>
|
||||
</g>
|
||||
<!-- A12->A13 -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>A12->A13</title>
|
||||
<path fill="none" stroke="#000000" d="M422.6543,-461.9134C422.3183,-429.4373 421.9719,-395.9527 421.6835,-368.0691"/>
|
||||
<polygon fill="none" stroke="#000000" points="419.1548,-461.9893 422.7581,-471.9525 426.1544,-461.9168 419.1548,-461.9893"/>
|
||||
<polygon fill="none" stroke="#000000" points="138.1165,-1900 138.1165,-1932 254.1165,-1932 254.1165,-1900 138.1165,-1900"/>
|
||||
<text text-anchor="start" x="147.7655" y="-1913" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><<AbstractIterMeta>></text>
|
||||
<polygon fill="none" stroke="#000000" points="138.1165,-1880 138.1165,-1900 254.1165,-1900 254.1165,-1880 138.1165,-1880"/>
|
||||
<polygon fill="none" stroke="#000000" points="138.1165,-1848 138.1165,-1880 254.1165,-1880 254.1165,-1848 138.1165,-1848"/>
|
||||
<text text-anchor="start" x="174.7265" y="-1861" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__iter__()</text>
|
||||
</g>
|
||||
<!-- A14 -->
|
||||
<g id="node15" class="node">
|
||||
<title>A14</title>
|
||||
<polygon fill="none" stroke="#000000" points="345,-1464 345,-1496 494,-1496 494,-1464 345,-1464"/>
|
||||
<text text-anchor="start" x="399.2175" y="-1477" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Message</text>
|
||||
<polygon fill="none" stroke="#000000" points="345,-1240 345,-1464 494,-1464 494,-1240 345,-1240"/>
|
||||
<text text-anchor="start" x="382.8265" y="-1445" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">server_side:bool</text>
|
||||
<text text-anchor="start" x="393.384" y="-1433" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb:Modbus</text>
|
||||
<text text-anchor="start" x="394.2185" y="-1421" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ifc:AsyncIfc</text>
|
||||
<text text-anchor="start" x="401.7135" y="-1409" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">node_id</text>
|
||||
<text text-anchor="start" x="380.043" y="-1397" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">header_valid:bool</text>
|
||||
<text text-anchor="start" x="394.49" y="-1385" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">header_len</text>
|
||||
<text text-anchor="start" x="400.324" y="-1373" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">data_len</text>
|
||||
<text text-anchor="start" x="397.8245" y="-1361" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">unique_id</text>
|
||||
<text text-anchor="start" x="391.715" y="-1349" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sug_area:str</text>
|
||||
<text text-anchor="start" x="388.656" y="-1337" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">new_data:dict</text>
|
||||
<text text-anchor="start" x="395.6" y="-1325" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">state:State</text>
|
||||
<text text-anchor="start" x="369.2045" y="-1313" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">shutdown_started:bool</text>
|
||||
<text text-anchor="start" x="388.3845" y="-1301" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">modbus_elms</text>
|
||||
<text text-anchor="start" x="384.507" y="-1289" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb_timer:Timer</text>
|
||||
<text text-anchor="start" x="393.385" y="-1277" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb_timeout</text>
|
||||
<text text-anchor="start" x="382.5525" y="-1265" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb_first_timeout</text>
|
||||
<text text-anchor="start" x="373.654" y="-1253" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">modbus_polling:bool</text>
|
||||
<polygon fill="none" stroke="#000000" points="345,-1136 345,-1240 494,-1240 494,-1136 345,-1136"/>
|
||||
<text text-anchor="start" x="368.3845" y="-1221" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_set_mqtt_timestamp()</text>
|
||||
<text text-anchor="start" x="397" y="-1209" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_timeout()</text>
|
||||
<text text-anchor="start" x="369.7675" y="-1197" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_send_modbus_cmd()</text>
|
||||
<text text-anchor="start" x="354.7595" y="-1185" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async> end_modbus_cmd()</text>
|
||||
<text text-anchor="start" x="404.5025" y="-1173" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
<text text-anchor="start" x="390.3305" y="-1161" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inc_counter()</text>
|
||||
<text text-anchor="start" x="388.6605" y="-1149" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dec_counter()</text>
|
||||
<polygon fill="none" stroke="#000000" points="151.1165,-1688 151.1165,-1720 241.1165,-1720 241.1165,-1688 151.1165,-1688"/>
|
||||
<text text-anchor="start" x="160.823" y="-1701" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><<ProtocolIfc>></text>
|
||||
<polygon fill="none" stroke="#000000" points="151.1165,-1656 151.1165,-1688 241.1165,-1688 241.1165,-1656 151.1165,-1656"/>
|
||||
<text text-anchor="start" x="176.95" y="-1669" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_registry</text>
|
||||
<polygon fill="none" stroke="#000000" points="151.1165,-1624 151.1165,-1656 241.1165,-1656 241.1165,-1624 151.1165,-1624"/>
|
||||
<text text-anchor="start" x="181.119" y="-1637" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A14->A6 -->
|
||||
<!-- A1->A14 -->
|
||||
<g id="edge14" class="edge">
|
||||
<title>A14->A6</title>
|
||||
<path fill="none" stroke="#000000" d="M456.7,-1135.7758C459.4656,-1122.5547 462.2514,-1109.2373 465.0066,-1096.0662"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="467.1066,-1086.0268 469.4637,-1096.7363 466.0828,-1090.9209 465.059,-1095.8149 465.059,-1095.8149 465.059,-1095.8149 466.0828,-1090.9209 460.6544,-1094.8935 467.1066,-1086.0268 467.1066,-1086.0268"/>
|
||||
<text text-anchor="middle" x="452.138" y="-1113.3031" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">use</text>
|
||||
<title>A1->A14</title>
|
||||
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M196.1165,-1837.756C196.1165,-1802.0883 196.1165,-1755.1755 196.1165,-1720.3644"/>
|
||||
<polygon fill="none" stroke="#000000" points="192.6166,-1837.9674 196.1165,-1847.9674 199.6166,-1837.9674 192.6166,-1837.9674"/>
|
||||
</g>
|
||||
<!-- A14->A11 -->
|
||||
<g id="edge17" class="edge">
|
||||
<title>A14->A11</title>
|
||||
<path fill="none" stroke="#000000" d="M387.4309,-1125.5329C364.9447,-989.8666 335.5291,-812.3923 316.9437,-700.2604"/>
|
||||
<polygon fill="none" stroke="#000000" points="384.0176,-1126.3448 389.1057,-1135.6378 390.9234,-1125.2001 384.0176,-1126.3448"/>
|
||||
<!-- A2 -->
|
||||
<g id="node3" class="node">
|
||||
<title>A2</title>
|
||||
<polygon fill="none" stroke="#000000" points="199.1165,-632 199.1165,-664 297.1165,-664 297.1165,-632 199.1165,-632"/>
|
||||
<text text-anchor="start" x="221.1665" y="-645" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InverterG3P</text>
|
||||
<polygon fill="none" stroke="#000000" points="199.1165,-576 199.1165,-632 297.1165,-632 297.1165,-576 199.1165,-576"/>
|
||||
<text text-anchor="start" x="238.1135" y="-613" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="208.6695" y="-601" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote:StreamPtr</text>
|
||||
<text text-anchor="start" x="213.9485" y="-589" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local:StreamPtr</text>
|
||||
<polygon fill="none" stroke="#000000" points="199.1165,-520 199.1165,-576 297.1165,-576 297.1165,-520 199.1165,-520"/>
|
||||
<text text-anchor="start" x="212.5585" y="-557" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">create_remote()</text>
|
||||
<text text-anchor="start" x="233.119" y="-533" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A15->A14 -->
|
||||
<!-- A3 -->
|
||||
<g id="node4" class="node">
|
||||
<title>A3</title>
|
||||
<polygon fill="none" stroke="#000000" points="415.4531,-320 318.7799,-320 318.7799,-284 415.4531,-284 415.4531,-320"/>
|
||||
<text text-anchor="middle" x="367.1165" y="-299" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">local:StreamPtr</text>
|
||||
</g>
|
||||
<!-- A2->A3 -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>A2->A3</title>
|
||||
<path fill="none" stroke="#000000" d="M282.2534,-508.8093C307.0525,-448.3743 339.0836,-370.3156 355.8099,-329.5539"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="282.2407,-508.8403 283.6635,-515.9097 277.6851,-519.942 276.2624,-512.8726 282.2407,-508.8403"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="359.6225,-320.2627 359.9893,-331.2224 357.7243,-324.8884 355.8262,-329.5141 355.8262,-329.5141 355.8262,-329.5141 357.7243,-324.8884 351.663,-327.8058 359.6225,-320.2627 359.6225,-320.2627"/>
|
||||
</g>
|
||||
<!-- A4 -->
|
||||
<g id="node5" class="node">
|
||||
<title>A4</title>
|
||||
<polygon fill="none" stroke="#000000" points="300.5106,-320 193.7224,-320 193.7224,-284 300.5106,-284 300.5106,-320"/>
|
||||
<text text-anchor="middle" x="247.1165" y="-299" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">remote:StreamPtr</text>
|
||||
</g>
|
||||
<!-- A2->A4 -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>A2->A4</title>
|
||||
<path fill="none" stroke="#000000" d="M247.8254,-507.5905C247.6188,-447.68 247.3542,-370.9429 247.214,-330.266"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="247.8265,-507.9421 251.8473,-513.9282 247.868,-519.942 243.8473,-513.9559 247.8265,-507.9421"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="247.1795,-320.2627 251.714,-330.2471 247.1968,-325.2627 247.2141,-330.2626 247.2141,-330.2626 247.2141,-330.2626 247.1968,-325.2627 242.7141,-330.2782 247.1795,-320.2627 247.1795,-320.2627"/>
|
||||
</g>
|
||||
<!-- A8 -->
|
||||
<g id="node9" class="node">
|
||||
<title>A8</title>
|
||||
<polygon fill="none" stroke="#000000" points="261.1165,-100 261.1165,-132 439.1165,-132 439.1165,-100 261.1165,-100"/>
|
||||
<text text-anchor="start" x="305.668" y="-113" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStreamServer</text>
|
||||
<polygon fill="none" stroke="#000000" points="261.1165,-68 261.1165,-100 439.1165,-100 439.1165,-68 261.1165,-68"/>
|
||||
<text text-anchor="start" x="317.8875" y="-81" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">create_remote</text>
|
||||
<polygon fill="none" stroke="#000000" points="261.1165,0 261.1165,-68 439.1165,-68 439.1165,0 261.1165,0"/>
|
||||
<text text-anchor="start" x="301.774" y="-49" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>server_loop()</text>
|
||||
<text text-anchor="start" x="292.605" y="-37" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>_async_forward()</text>
|
||||
<text text-anchor="start" x="270.9255" y="-25" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>publish_outstanding_mqtt()</text>
|
||||
<text text-anchor="start" x="335.119" y="-13" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A3->A8 -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>A3->A8</title>
|
||||
<path fill="none" stroke="#000000" d="M364.9314,-271.6651C362.5869,-239.1181 358.7725,-186.1658 355.6014,-142.1431"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="364.9485,-271.9044 369.3693,-277.6014 365.8108,-283.8733 361.39,-278.1763 364.9485,-271.9044"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="354.8731,-132.0321 360.08,-141.6829 355.2323,-137.0192 355.5916,-142.0063 355.5916,-142.0063 355.5916,-142.0063 355.2323,-137.0192 351.1032,-142.3296 354.8731,-132.0321 354.8731,-132.0321"/>
|
||||
</g>
|
||||
<!-- A9 -->
|
||||
<g id="node10" class="node">
|
||||
<title>A9</title>
|
||||
<polygon fill="none" stroke="#000000" points="89.1165,-82 89.1165,-114 227.1165,-114 227.1165,-82 89.1165,-82"/>
|
||||
<text text-anchor="start" x="115.6135" y="-95" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStreamClient</text>
|
||||
<polygon fill="none" stroke="#000000" points="89.1165,-62 89.1165,-82 227.1165,-82 227.1165,-62 89.1165,-62"/>
|
||||
<polygon fill="none" stroke="#000000" points="89.1165,-18 89.1165,-62 227.1165,-62 227.1165,-18 89.1165,-18"/>
|
||||
<text text-anchor="start" x="111.9945" y="-43" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>client_loop()</text>
|
||||
<text text-anchor="start" x="98.9405" y="-31" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>_async_forward())</text>
|
||||
</g>
|
||||
<!-- A4->A9 -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>A4->A9</title>
|
||||
<path fill="none" stroke="#000000" d="M240.2806,-283.8733C227.5204,-250.0372 199.5834,-175.9573 179.8383,-123.5994"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="176.2523,-114.0904 183.9915,-121.8593 178.0166,-118.7688 179.781,-123.4472 179.781,-123.4472 179.781,-123.4472 178.0166,-118.7688 175.5704,-125.0351 176.2523,-114.0904 176.2523,-114.0904"/>
|
||||
<text text-anchor="middle" x="225.9759" y="-266.8956" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
|
||||
</g>
|
||||
<!-- A5 -->
|
||||
<g id="node6" class="node">
|
||||
<title>A5</title>
|
||||
<polygon fill="none" stroke="#000000" points="145.1165,-1054 145.1165,-1086 262.1165,-1086 262.1165,-1054 145.1165,-1054"/>
|
||||
<text text-anchor="start" x="173.0455" y="-1067" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><<AsyncIfc>></text>
|
||||
<polygon fill="none" stroke="#000000" points="145.1165,-1034 145.1165,-1054 262.1165,-1054 262.1165,-1034 145.1165,-1034"/>
|
||||
<polygon fill="none" stroke="#000000" points="145.1165,-762 145.1165,-1034 262.1165,-1034 262.1165,-762 145.1165,-762"/>
|
||||
<text text-anchor="start" x="173.0525" y="-1015" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">set_node_id()</text>
|
||||
<text text-anchor="start" x="171.3825" y="-1003" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">get_conn_no()</text>
|
||||
<text text-anchor="start" x="185.28" y="-979" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_add()</text>
|
||||
<text text-anchor="start" x="183.0605" y="-967" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_flush()</text>
|
||||
<text text-anchor="start" x="186.67" y="-955" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_get()</text>
|
||||
<text text-anchor="start" x="182.78" y="-943" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_peek()</text>
|
||||
<text text-anchor="start" x="186.95" y="-931" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_log()</text>
|
||||
<text text-anchor="start" x="182.7855" y="-919" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_clear()</text>
|
||||
<text text-anchor="start" x="186.95" y="-907" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_len()</text>
|
||||
<text text-anchor="start" x="181.391" y="-883" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_add()</text>
|
||||
<text text-anchor="start" x="183.061" y="-871" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_log()</text>
|
||||
<text text-anchor="start" x="186.395" y="-859" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_get()</text>
|
||||
<text text-anchor="start" x="182.505" y="-847" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_peek()</text>
|
||||
<text text-anchor="start" x="186.675" y="-835" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_log()</text>
|
||||
<text text-anchor="start" x="182.5105" y="-823" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_clear()</text>
|
||||
<text text-anchor="start" x="186.675" y="-811" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_len()</text>
|
||||
<text text-anchor="start" x="178.6155" y="-799" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_set_cb()</text>
|
||||
<text text-anchor="start" x="154.996" y="-775" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">prot_set_timeout_cb()</text>
|
||||
</g>
|
||||
<!-- A6 -->
|
||||
<g id="node7" class="node">
|
||||
<title>A6</title>
|
||||
<polygon fill="none" stroke="#000000" points="84.1165,-622 84.1165,-654 177.1165,-654 177.1165,-622 84.1165,-622"/>
|
||||
<text text-anchor="start" x="102.2805" y="-635" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncIfcImpl</text>
|
||||
<polygon fill="none" stroke="#000000" points="84.1165,-530 84.1165,-622 177.1165,-622 177.1165,-530 84.1165,-530"/>
|
||||
<text text-anchor="start" x="93.6645" y="-603" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">fwd_fifo:ByteFifo</text>
|
||||
<text text-anchor="start" x="97.5535" y="-591" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tx_fifo:ByteFifo</text>
|
||||
<text text-anchor="start" x="97.2785" y="-579" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rx_fifo:ByteFifo</text>
|
||||
<text text-anchor="start" x="96.7125" y="-567" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">conn_no:Count</text>
|
||||
<text text-anchor="start" x="112.83" y="-555" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">node_id</text>
|
||||
<text text-anchor="start" x="106.166" y="-543" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">timeout_cb</text>
|
||||
</g>
|
||||
<!-- A5->A6 -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>A5->A6</title>
|
||||
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M165.2976,-752.0017C157.592,-716.9571 149.9649,-682.2694 143.7924,-654.1971"/>
|
||||
<polygon fill="none" stroke="#000000" points="161.906,-752.8753 167.4719,-761.8903 168.7427,-751.372 161.906,-752.8753"/>
|
||||
</g>
|
||||
<!-- A7 -->
|
||||
<g id="node8" class="node">
|
||||
<title>A7</title>
|
||||
<polygon fill="none" stroke="#000000" points="74.1165,-390 74.1165,-422 176.1165,-422 176.1165,-390 74.1165,-390"/>
|
||||
<text text-anchor="start" x="95.3905" y="-403" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">AsyncStream</text>
|
||||
<polygon fill="none" stroke="#000000" points="74.1165,-310 74.1165,-390 176.1165,-390 176.1165,-310 74.1165,-310"/>
|
||||
<text text-anchor="start" x="110.6695" y="-371" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">reader</text>
|
||||
<text text-anchor="start" x="112.8995" y="-359" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">writer</text>
|
||||
<text text-anchor="start" x="115.1135" y="-347" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="110.6695" y="-335" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">r_addr</text>
|
||||
<text text-anchor="start" x="111.2245" y="-323" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">l_addr</text>
|
||||
<polygon fill="none" stroke="#000000" points="74.1165,-182 74.1165,-310 176.1165,-310 176.1165,-182 74.1165,-182"/>
|
||||
<text text-anchor="start" x="96.7705" y="-279" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async>loop</text>
|
||||
<text text-anchor="start" x="112.8985" y="-267" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">disc()</text>
|
||||
<text text-anchor="start" x="110.119" y="-255" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
<text text-anchor="start" x="105.6705" y="-243" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
|
||||
<text text-anchor="start" x="90.387" y="-219" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_read()</text>
|
||||
<text text-anchor="start" x="89.8375" y="-207" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_write()</text>
|
||||
<text text-anchor="start" x="83.7235" y="-195" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">__async_forward()</text>
|
||||
</g>
|
||||
<!-- A6->A7 -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>A6->A7</title>
|
||||
<path fill="none" stroke="#000000" d="M128.868,-519.5861C128.3592,-490.0737 127.7571,-455.1552 127.186,-422.0295"/>
|
||||
<polygon fill="none" stroke="#000000" points="125.3719,-519.8496 129.0439,-529.7877 132.3709,-519.7288 125.3719,-519.8496"/>
|
||||
</g>
|
||||
<!-- A7->A8 -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>A7->A8</title>
|
||||
<path fill="none" stroke="#000000" d="M182.5777,-185.0204C183.4154,-184.0001 184.2616,-182.9929 185.1165,-182 206.4788,-157.1889 234.2469,-135.0276 260.8921,-116.8901"/>
|
||||
<polygon fill="none" stroke="#000000" points="179.6875,-183.0361 176.3256,-193.0834 185.2193,-187.3255 179.6875,-183.0361"/>
|
||||
</g>
|
||||
<!-- A7->A9 -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>A7->A9</title>
|
||||
<path fill="none" stroke="#000000" d="M143.3214,-171.8077C146.1952,-151.2556 148.9992,-131.2022 151.3799,-114.1772"/>
|
||||
<polygon fill="none" stroke="#000000" points="139.8252,-171.5375 141.9065,-181.9259 146.7577,-172.5069 139.8252,-171.5375"/>
|
||||
</g>
|
||||
<!-- A10 -->
|
||||
<g id="node11" class="node">
|
||||
<title>A10</title>
|
||||
<polygon fill="none" stroke="#000000" points="318.1165,-668 318.1165,-700 409.1165,-700 409.1165,-668 318.1165,-668"/>
|
||||
<text text-anchor="start" x="336.1115" y="-681" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">SolarmanV5</text>
|
||||
<polygon fill="none" stroke="#000000" points="318.1165,-552 318.1165,-668 409.1165,-668 409.1165,-552 318.1165,-552"/>
|
||||
<text text-anchor="start" x="344.4395" y="-649" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">conn_no</text>
|
||||
<text text-anchor="start" x="353.6135" y="-637" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">addr</text>
|
||||
<text text-anchor="start" x="348.6145" y="-613" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">control</text>
|
||||
<text text-anchor="start" x="351.674" y="-601" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">serial</text>
|
||||
<text text-anchor="start" x="356.6725" y="-589" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">snr</text>
|
||||
<text text-anchor="start" x="335.8265" y="-577" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">db:InfosG3P</text>
|
||||
<text text-anchor="start" x="349.7285" y="-565" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">switch</text>
|
||||
<polygon fill="none" stroke="#000000" points="318.1165,-484 318.1165,-552 409.1165,-552 409.1165,-484 318.1165,-484"/>
|
||||
<text text-anchor="start" x="328.057" y="-533" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">msg_unknown()</text>
|
||||
<text text-anchor="start" x="344.1705" y="-509" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">healthy()</text>
|
||||
<text text-anchor="start" x="348.619" y="-497" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A10->A3 -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>A10->A3</title>
|
||||
<path fill="none" stroke="#000000" d="M364.7507,-473.5237C365.4625,-421.9136 366.2384,-365.6622 366.7008,-332.138"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="364.6116,-483.6023 360.2501,-473.5412 364.6806,-478.6028 364.7497,-473.6033 364.7497,-473.6033 364.7497,-473.6033 364.6806,-478.6028 369.2492,-473.6654 364.6116,-483.6023 364.6116,-483.6023"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="366.7019,-332.0519 362.7851,-325.9973 366.8675,-320.053 370.7843,-326.1077 366.7019,-332.0519"/>
|
||||
</g>
|
||||
<!-- A10->A4 -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>A10->A4</title>
|
||||
<path fill="none" stroke="#000000" d="M316.0157,-474.2481C292.5547,-415.5956 266.6257,-350.7729 254.3377,-320.053"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="319.7574,-483.6023 311.8653,-475.9888 317.9004,-478.9599 316.0435,-474.3175 316.0435,-474.3175 316.0435,-474.3175 317.9004,-478.9599 320.2216,-472.6462 319.7574,-483.6023 319.7574,-483.6023"/>
|
||||
<text text-anchor="middle" x="268.9174" y="-330.7436" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
|
||||
</g>
|
||||
<!-- A12 -->
|
||||
<g id="node13" class="node">
|
||||
<title>A12</title>
|
||||
<polygon fill="none" stroke="#000000" points="434.1165,-336 434.1165,-368 529.1165,-368 529.1165,-336 434.1165,-336"/>
|
||||
<text text-anchor="start" x="460.775" y="-349" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">InfosG3P</text>
|
||||
<polygon fill="none" stroke="#000000" points="434.1165,-304 434.1165,-336 529.1165,-336 529.1165,-304 434.1165,-304"/>
|
||||
<text text-anchor="start" x="443.829" y="-317" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">client_mode:bool</text>
|
||||
<polygon fill="none" stroke="#000000" points="434.1165,-236 434.1165,-304 529.1165,-304 529.1165,-236 434.1165,-236"/>
|
||||
<text text-anchor="start" x="458.0005" y="-285" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_confs()</text>
|
||||
<text text-anchor="start" x="465.7845" y="-273" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">parse()</text>
|
||||
<text text-anchor="start" x="469.3985" y="-261" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">calc()</text>
|
||||
<text text-anchor="start" x="467.73" y="-249" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">build()</text>
|
||||
</g>
|
||||
<!-- A10->A12 -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>A10->A12</title>
|
||||
<path fill="none" stroke="#000000" d="M407.2231,-483.6023C421.5819,-448.3138 437.2,-409.9305 450.3629,-377.5809"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="454.1856,-368.1861 454.5848,-379.1447 452.3011,-372.8174 450.4166,-377.4487 450.4166,-377.4487 450.4166,-377.4487 452.3011,-372.8174 446.2485,-375.7526 454.1856,-368.1861 454.1856,-368.1861"/>
|
||||
</g>
|
||||
<!-- A11 -->
|
||||
<g id="node12" class="node">
|
||||
<title>A11</title>
|
||||
<polygon fill="none" stroke="#000000" points="430.1165,-680 430.1165,-712 533.1165,-712 533.1165,-680 430.1165,-680"/>
|
||||
<text text-anchor="start" x="470.7785" y="-693" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Infos</text>
|
||||
<polygon fill="none" stroke="#000000" points="430.1165,-624 430.1165,-680 533.1165,-680 533.1165,-624 430.1165,-624"/>
|
||||
<text text-anchor="start" x="473.558" y="-661" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">stat</text>
|
||||
<text text-anchor="start" x="449.1025" y="-649" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">new_stat_data</text>
|
||||
<text text-anchor="start" x="462.72" y="-637" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">info_dev</text>
|
||||
<polygon fill="none" stroke="#000000" points="430.1165,-472 430.1165,-624 533.1165,-624 533.1165,-472 430.1165,-472"/>
|
||||
<text text-anchor="start" x="457.452" y="-605" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">static_init()</text>
|
||||
<text text-anchor="start" x="455.501" y="-593" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dev_value()</text>
|
||||
<text text-anchor="start" x="452.447" y="-581" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inc_counter()</text>
|
||||
<text text-anchor="start" x="450.777" y="-569" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dec_counter()</text>
|
||||
<text text-anchor="start" x="448.8265" y="-557" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_proxy_conf</text>
|
||||
<text text-anchor="start" x="463.8295" y="-545" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_conf</text>
|
||||
<text text-anchor="start" x="456.6105" y="-533" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ha_remove</text>
|
||||
<text text-anchor="start" x="457.991" y="-521" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">update_db</text>
|
||||
<text text-anchor="start" x="442.1535" y="-509" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">set_db_def_value</text>
|
||||
<text text-anchor="start" x="451.602" y="-497" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">get_db_value</text>
|
||||
<text text-anchor="start" x="439.939" y="-485" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ignore_this_device</text>
|
||||
</g>
|
||||
<!-- A11->A12 -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>A11->A12</title>
|
||||
<path fill="none" stroke="#000000" d="M481.1165,-461.9134C481.1165,-429.4373 481.1165,-395.9527 481.1165,-368.0691"/>
|
||||
<polygon fill="none" stroke="#000000" points="477.6166,-461.9525 481.1165,-471.9525 484.6166,-461.9526 477.6166,-461.9525"/>
|
||||
</g>
|
||||
<!-- A13 -->
|
||||
<g id="node14" class="node">
|
||||
<title>A13</title>
|
||||
<polygon fill="none" stroke="#000000" points="172.1165,-1464 172.1165,-1496 321.1165,-1496 321.1165,-1464 172.1165,-1464"/>
|
||||
<text text-anchor="start" x="226.334" y="-1477" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Message</text>
|
||||
<polygon fill="none" stroke="#000000" points="172.1165,-1240 172.1165,-1464 321.1165,-1464 321.1165,-1240 172.1165,-1240"/>
|
||||
<text text-anchor="start" x="209.943" y="-1445" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">server_side:bool</text>
|
||||
<text text-anchor="start" x="220.5005" y="-1433" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb:Modbus</text>
|
||||
<text text-anchor="start" x="221.335" y="-1421" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">ifc:AsyncIfc</text>
|
||||
<text text-anchor="start" x="228.83" y="-1409" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">node_id</text>
|
||||
<text text-anchor="start" x="207.1595" y="-1397" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">header_valid:bool</text>
|
||||
<text text-anchor="start" x="221.6065" y="-1385" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">header_len</text>
|
||||
<text text-anchor="start" x="227.4405" y="-1373" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">data_len</text>
|
||||
<text text-anchor="start" x="224.941" y="-1361" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">unique_id</text>
|
||||
<text text-anchor="start" x="218.8315" y="-1349" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">sug_area:str</text>
|
||||
<text text-anchor="start" x="215.7725" y="-1337" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">new_data:dict</text>
|
||||
<text text-anchor="start" x="222.7165" y="-1325" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">state:State</text>
|
||||
<text text-anchor="start" x="196.321" y="-1313" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">shutdown_started:bool</text>
|
||||
<text text-anchor="start" x="215.501" y="-1301" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">modbus_elms</text>
|
||||
<text text-anchor="start" x="211.6235" y="-1289" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb_timer:Timer</text>
|
||||
<text text-anchor="start" x="220.5015" y="-1277" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb_timeout</text>
|
||||
<text text-anchor="start" x="209.669" y="-1265" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">mb_first_timeout</text>
|
||||
<text text-anchor="start" x="200.7705" y="-1253" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">modbus_polling:bool</text>
|
||||
<polygon fill="none" stroke="#000000" points="172.1165,-1136 172.1165,-1240 321.1165,-1240 321.1165,-1136 172.1165,-1136"/>
|
||||
<text text-anchor="start" x="195.501" y="-1221" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_set_mqtt_timestamp()</text>
|
||||
<text text-anchor="start" x="224.1165" y="-1209" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_timeout()</text>
|
||||
<text text-anchor="start" x="196.884" y="-1197" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">_send_modbus_cmd()</text>
|
||||
<text text-anchor="start" x="181.876" y="-1185" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"><async> end_modbus_cmd()</text>
|
||||
<text text-anchor="start" x="231.619" y="-1173" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
<text text-anchor="start" x="217.447" y="-1161" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">inc_counter()</text>
|
||||
<text text-anchor="start" x="215.777" y="-1149" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">dec_counter()</text>
|
||||
</g>
|
||||
<!-- A13->A5 -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>A13->A5</title>
|
||||
<path fill="none" stroke="#000000" d="M226.347,-1135.7758C224.8967,-1122.5547 223.4359,-1109.2373 221.9911,-1096.0662"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="220.8898,-1086.0268 226.4535,-1095.4764 221.4351,-1090.997 221.9803,-1095.9672 221.9803,-1095.9672 221.9803,-1095.9672 221.4351,-1090.997 217.5072,-1096.4579 220.8898,-1086.0268 220.8898,-1086.0268"/>
|
||||
<text text-anchor="middle" x="215.9686" y="-1115.6794" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">use</text>
|
||||
</g>
|
||||
<!-- A13->A10 -->
|
||||
<g id="edge16" class="edge">
|
||||
<title>A15->A14</title>
|
||||
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M377.1741,-1613.8004C381.7377,-1581.3079 387.6971,-1538.8764 393.681,-1496.2713"/>
|
||||
<polygon fill="none" stroke="#000000" points="373.6682,-1613.5986 375.7432,-1623.9883 380.6001,-1614.5723 373.6682,-1613.5986"/>
|
||||
<title>A13->A10</title>
|
||||
<path fill="none" stroke="#000000" d="M276.8964,-1125.5329C298.8204,-989.8666 327.5006,-812.3923 345.6214,-700.2604"/>
|
||||
<polygon fill="none" stroke="#000000" points="273.4037,-1125.2075 275.2634,-1135.6378 280.314,-1126.3243 273.4037,-1125.2075"/>
|
||||
</g>
|
||||
<!-- A16 -->
|
||||
<g id="node17" class="node">
|
||||
<title>A16</title>
|
||||
<polygon fill="none" stroke="#000000" points="433,-1766 433,-1798 508,-1798 508,-1766 433,-1766"/>
|
||||
<text text-anchor="start" x="452.7175" y="-1779" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Modbus</text>
|
||||
<polygon fill="none" stroke="#000000" points="433,-1614 433,-1766 508,-1766 508,-1614 433,-1614"/>
|
||||
<text text-anchor="start" x="462.1615" y="-1747" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">que</text>
|
||||
<text text-anchor="start" x="442.99" y="-1723" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">snd_handler</text>
|
||||
<text text-anchor="start" x="444.105" y="-1711" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rsp_handler</text>
|
||||
<text text-anchor="start" x="454.1085" y="-1699" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">timeout</text>
|
||||
<text text-anchor="start" x="444.3895" y="-1687" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">max_retires</text>
|
||||
<text text-anchor="start" x="452.442" y="-1675" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">last_xxx</text>
|
||||
<text text-anchor="start" x="464.3915" y="-1663" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">err</text>
|
||||
<text text-anchor="start" x="451.0535" y="-1651" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">retry_cnt</text>
|
||||
<text text-anchor="start" x="449.379" y="-1639" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">req_pend</text>
|
||||
<text text-anchor="start" x="463.8365" y="-1627" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tim</text>
|
||||
<polygon fill="none" stroke="#000000" points="433,-1546 433,-1614 508,-1614 508,-1546 433,-1546"/>
|
||||
<text text-anchor="start" x="444.39" y="-1595" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">build_msg()</text>
|
||||
<text text-anchor="start" x="447.724" y="-1583" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">recv_req()</text>
|
||||
<text text-anchor="start" x="445.224" y="-1571" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">recv_resp()</text>
|
||||
<text text-anchor="start" x="455.5025" y="-1559" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
<!-- A14->A13 -->
|
||||
<g id="edge15" class="edge">
|
||||
<title>A14->A13</title>
|
||||
<path fill="none" stroke="#000000" stroke-dasharray="5,2" d="M204.2906,-1613.8004C208.8542,-1581.3079 214.8136,-1538.8764 220.7975,-1496.2713"/>
|
||||
<polygon fill="none" stroke="#000000" points="200.7847,-1613.5986 202.8597,-1623.9883 207.7166,-1614.5723 200.7847,-1613.5986"/>
|
||||
</g>
|
||||
<!-- A16->A14 -->
|
||||
<g id="edge18" class="edge">
|
||||
<title>A16->A14</title>
|
||||
<path fill="none" stroke="#000000" d="M450.5227,-1536.041C448.6468,-1522.9463 446.7248,-1509.5297 444.8004,-1496.0971"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="451.9475,-1545.9867 446.0748,-1536.726 451.2384,-1541.0373 450.5293,-1536.0878 450.5293,-1536.0878 450.5293,-1536.0878 451.2384,-1541.0373 454.9839,-1535.4496 451.9475,-1545.9867 451.9475,-1545.9867"/>
|
||||
<text text-anchor="middle" x="455.7379" y="-1509.8414" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">has</text>
|
||||
<text text-anchor="middle" x="441.0101" y="-1526.2424" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
|
||||
<!-- A15 -->
|
||||
<g id="node16" class="node">
|
||||
<title>A15</title>
|
||||
<polygon fill="none" stroke="#000000" points="260.1165,-1766 260.1165,-1798 335.1165,-1798 335.1165,-1766 260.1165,-1766"/>
|
||||
<text text-anchor="start" x="279.834" y="-1779" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">Modbus</text>
|
||||
<polygon fill="none" stroke="#000000" points="260.1165,-1614 260.1165,-1766 335.1165,-1766 335.1165,-1614 260.1165,-1614"/>
|
||||
<text text-anchor="start" x="289.278" y="-1747" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">que</text>
|
||||
<text text-anchor="start" x="270.1065" y="-1723" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">snd_handler</text>
|
||||
<text text-anchor="start" x="271.2215" y="-1711" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">rsp_handler</text>
|
||||
<text text-anchor="start" x="281.225" y="-1699" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">timeout</text>
|
||||
<text text-anchor="start" x="271.506" y="-1687" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">max_retires</text>
|
||||
<text text-anchor="start" x="279.5585" y="-1675" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">last_xxx</text>
|
||||
<text text-anchor="start" x="291.508" y="-1663" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">err</text>
|
||||
<text text-anchor="start" x="278.17" y="-1651" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">retry_cnt</text>
|
||||
<text text-anchor="start" x="276.4955" y="-1639" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">req_pend</text>
|
||||
<text text-anchor="start" x="290.953" y="-1627" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">tim</text>
|
||||
<polygon fill="none" stroke="#000000" points="260.1165,-1546 260.1165,-1614 335.1165,-1614 335.1165,-1546 260.1165,-1546"/>
|
||||
<text text-anchor="start" x="271.5065" y="-1595" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">build_msg()</text>
|
||||
<text text-anchor="start" x="274.8405" y="-1583" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">recv_req()</text>
|
||||
<text text-anchor="start" x="272.3405" y="-1571" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">recv_resp()</text>
|
||||
<text text-anchor="start" x="282.619" y="-1559" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">close()</text>
|
||||
</g>
|
||||
<!-- A15->A13 -->
|
||||
<g id="edge17" class="edge">
|
||||
<title>A15->A13</title>
|
||||
<path fill="none" stroke="#000000" d="M277.6392,-1536.041C275.7633,-1522.9463 273.8413,-1509.5297 271.9169,-1496.0971"/>
|
||||
<polygon fill="#000000" stroke="#000000" points="279.064,-1545.9867 273.1913,-1536.726 278.3549,-1541.0373 277.6458,-1536.0878 277.6458,-1536.0878 277.6458,-1536.0878 278.3549,-1541.0373 282.1004,-1535.4496 279.064,-1545.9867 279.064,-1545.9867"/>
|
||||
<text text-anchor="middle" x="282.8544" y="-1509.8414" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">has</text>
|
||||
<text text-anchor="middle" x="268.1266" y="-1526.2424" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">0..1</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
@@ -5,10 +5,9 @@
|
||||
[note: Example of instantiation for a GEN3PLUS inverter!{bg:cornsilk}]
|
||||
[<<AbstractIterMeta>>||__iter__()]
|
||||
|
||||
[InverterBase|addr;remote:StreamPtr;local:StreamPtr|create_remote();;close()]
|
||||
[InverterBase]^[InverterG3P|forward_at_cmd_resp;]
|
||||
[InverterBase]++->[local:StreamPtr]
|
||||
[InverterBase]++->[remote:StreamPtr]
|
||||
[InverterG3P|addr;remote:StreamPtr;local:StreamPtr|create_remote();;close()]
|
||||
[InverterG3P]++->[local:StreamPtr]
|
||||
[InverterG3P]++->[remote:StreamPtr]
|
||||
|
||||
[<<AsyncIfc>>||set_node_id();get_conn_no();;tx_add();tx_flush();tx_get();tx_peek();tx_log();tx_clear();tx_len();;fwd_add();fwd_log();rx_get();rx_peek();rx_log();rx_clear();rx_len();rx_set_cb();;prot_set_timeout_cb()]
|
||||
[AsyncIfcImpl|fwd_fifo:ByteFifo;tx_fifo:ByteFifo;rx_fifo:ByteFifo;conn_no:Count;node_id;timeout_cb]
|
||||
@@ -20,7 +19,7 @@
|
||||
[AsyncStream]^[AsyncStreamServer]
|
||||
[AsyncStream]^[AsyncStreamClient]
|
||||
|
||||
[SolarmanV5|conn_no;addr;inverter:InverterG3P;control;serial;snr;db:InfosG3P;switch|msg_unknown();;healthy();close()]
|
||||
[SolarmanV5|conn_no;addr;;control;serial;snr;db:InfosG3P;switch|msg_unknown();;healthy();close()]
|
||||
[SolarmanV5]<-++[local:StreamPtr]
|
||||
[local:StreamPtr]++->[AsyncStreamServer]
|
||||
[SolarmanV5]<-0..1[remote:StreamPtr]
|
||||
|
||||
@@ -23,7 +23,7 @@ if [ "$user" = '0' ]; then
|
||||
echo "######################################################"
|
||||
echo "#"
|
||||
|
||||
exec su-exec $SERVICE_NAME "$@" -tr './translations/'
|
||||
exec su-exec $SERVICE_NAME "$@"
|
||||
else
|
||||
exec "$@"
|
||||
fi
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
flake8==7.3.0
|
||||
pytest==8.4.1
|
||||
pytest-asyncio==1.1.0
|
||||
pytest-cov==6.2.1
|
||||
python-dotenv==1.1.1
|
||||
flake8==7.1.2
|
||||
pytest==8.3.5
|
||||
pytest-asyncio==0.26.0
|
||||
pytest-cov==6.0.0
|
||||
python-dotenv==1.1.0
|
||||
mock==5.2.0
|
||||
coverage==7.9.2
|
||||
coverage==7.7.1
|
||||
jinja2-cli==0.8.2
|
||||
@@ -1,5 +1,4 @@
|
||||
aiomqtt==2.4.0
|
||||
aiomqtt==2.3.0
|
||||
schema==0.7.7
|
||||
aiocron==2.1
|
||||
quart==0.20
|
||||
quart-babel==1.0.7
|
||||
aiohttp==3.11.14
|
||||
@@ -1,3 +0,0 @@
|
||||
[python: **.py]
|
||||
[jinja2: web/templates/**.html]
|
||||
[jinja2: web/templates/**.html.j2]
|
||||
@@ -327,10 +327,8 @@ class AsyncStreamServer(AsyncStream):
|
||||
logger.info(f'[{self.node_id}:{self.conn_no}] '
|
||||
f'Accept connection from {self.r_addr}')
|
||||
Infos.inc_counter('Inverter_Cnt')
|
||||
Infos.inc_counter('ServerMode_Cnt')
|
||||
await self.publish_outstanding_mqtt()
|
||||
await self.loop()
|
||||
Infos.dec_counter('ServerMode_Cnt')
|
||||
Infos.dec_counter('Inverter_Cnt')
|
||||
await self.publish_outstanding_mqtt()
|
||||
logger.info(f'[{self.node_id}:{self.conn_no}] Server loop stopped for'
|
||||
@@ -361,11 +359,9 @@ class AsyncStreamServer(AsyncStream):
|
||||
|
||||
class AsyncStreamClient(AsyncStream):
|
||||
def __init__(self, reader: StreamReader, writer: StreamWriter,
|
||||
rstream: "StreamPtr", close_cb,
|
||||
use_emu: bool = False) -> None:
|
||||
rstream: "StreamPtr", close_cb) -> None:
|
||||
AsyncStream.__init__(self, reader, writer, rstream)
|
||||
self.close_cb = close_cb
|
||||
self.emu_mode = use_emu
|
||||
|
||||
async def disc(self) -> None:
|
||||
logging.debug('AsyncStreamClient.disc()')
|
||||
@@ -380,16 +376,8 @@ class AsyncStreamClient(AsyncStream):
|
||||
async def client_loop(self, _: str) -> None:
|
||||
'''Loop for receiving messages from the TSUN cloud (client-side)'''
|
||||
Infos.inc_counter('Cloud_Conn_Cnt')
|
||||
if self.emu_mode:
|
||||
Infos.inc_counter('EmuMode_Cnt')
|
||||
else:
|
||||
Infos.inc_counter('ProxyMode_Cnt')
|
||||
await self.publish_outstanding_mqtt()
|
||||
await self.loop()
|
||||
if self.emu_mode:
|
||||
Infos.dec_counter('EmuMode_Cnt')
|
||||
else:
|
||||
Infos.dec_counter('ProxyMode_Cnt')
|
||||
Infos.dec_counter('Cloud_Conn_Cnt')
|
||||
await self.publish_outstanding_mqtt()
|
||||
logger.info(f'[{self.node_id}:{self.conn_no}] '
|
||||
|
||||
@@ -162,25 +162,22 @@ class Config():
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def init(cls, def_reader: ConfigIfc, log_path: str = '',
|
||||
cnf_path: str = 'config') -> None | str:
|
||||
def init(cls, def_reader: ConfigIfc) -> None | str:
|
||||
'''Initialise the Proxy-Config
|
||||
|
||||
Copy the internal default config file into the config directory
|
||||
and initialise the Config with the default configuration '''
|
||||
cls.err = None
|
||||
cls.log_path = log_path
|
||||
cls.def_config = {}
|
||||
try:
|
||||
# make the default config transparaent by copying it
|
||||
# in the config.example file
|
||||
logging.info(
|
||||
f'Copy Default Config to {cnf_path}config.example.toml')
|
||||
logging.debug('Copy Default Config to config.example.toml')
|
||||
|
||||
shutil.copy2("cnf/default_config.toml",
|
||||
cnf_path + "config.example.toml")
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
shutil.copy2("default_config.toml",
|
||||
"config/config.example.toml")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# read example config file as default configuration
|
||||
try:
|
||||
@@ -250,7 +247,3 @@ here. The default config reader is handled in the Config.init method'''
|
||||
'''Check if the member is the default value'''
|
||||
|
||||
return cls.act_config.get(member) == cls.def_config.get(member)
|
||||
|
||||
@classmethod
|
||||
def get_log_path(cls) -> str:
|
||||
return cls.log_path
|
||||
|
||||
@@ -34,11 +34,10 @@ class Control:
|
||||
class Talent(Message):
|
||||
TXT_UNKNOWN_CTRL = 'Unknown Ctrl'
|
||||
|
||||
def __init__(self, inverter, addr, ifc: "AsyncIfc", server_side: bool,
|
||||
def __init__(self, addr, ifc: "AsyncIfc", server_side: bool,
|
||||
client_mode: bool = False, id_str=b''):
|
||||
super().__init__('G3', ifc, server_side, self.send_modbus_cb,
|
||||
mb_timeout=15)
|
||||
_ = inverter
|
||||
ifc.rx_set_cb(self.read)
|
||||
ifc.prot_set_timeout_cb(self._timeout)
|
||||
ifc.prot_set_init_new_client_conn_cb(self._init_new_client_conn)
|
||||
@@ -100,7 +99,7 @@ class Talent(Message):
|
||||
|
||||
if serial_no in inverters:
|
||||
inv = inverters[serial_no]
|
||||
self._set_config_parms(inv, serial_no)
|
||||
self._set_config_parms(inv)
|
||||
self.db.set_pv_module_details(inv)
|
||||
logger.debug(f'SerialNo {serial_no} allowed! area:{self.sug_area}') # noqa: E501
|
||||
else:
|
||||
|
||||
@@ -19,19 +19,6 @@ class RegisterFunc:
|
||||
result += prod
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def cmp_values(info: Infos, params: map) -> None | int:
|
||||
try:
|
||||
val = info.get_db_value(params['reg'])
|
||||
if val < params['cmp_val']:
|
||||
return params['res'][0]
|
||||
if val == params['cmp_val']:
|
||||
return params['res'][1]
|
||||
return params['res'][2]
|
||||
except Exception:
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
class RegisterMap:
|
||||
# make the class read/only by using __slots__
|
||||
@@ -144,54 +131,52 @@ class RegisterMap:
|
||||
0x4201000c: {'reg': Register.SENSOR_LIST, 'fmt': '<H', 'func': Fmt.hex4}, # noqa: E501
|
||||
0x4201001c: {'reg': Register.POWER_ON_TIME, 'fmt': '<H', 'ratio': 1, 'dep': ProxyMode.SERVER}, # noqa: E501, or packet number
|
||||
0x42010020: {'reg': Register.SERIAL_NUMBER, 'fmt': '!16s'}, # noqa: E501
|
||||
0x42010030: {'reg': Register.BATT_PV1_VOLT, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, DC Voltage PV1
|
||||
0x42010032: {'reg': Register.BATT_PV1_CUR, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, DC Current PV1
|
||||
0x42010034: {'reg': Register.BATT_PV2_VOLT, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, DC Voltage PV2
|
||||
0x42010036: {'reg': Register.BATT_PV2_CUR, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, DC Current PV2
|
||||
0x42010038: {'reg': Register.BATT_TOTAL_CHARG, 'fmt': '!L', 'ratio': 0.01}, # noqa: E501
|
||||
0x4201003c: {'reg': Register.BATT_PV1_STATUS, 'fmt': '!H'}, # noqa: E501 MPTT-1 Operating Status: 0(Standby), 1(Work)
|
||||
0x4201003e: {'reg': Register.BATT_PV2_STATUS, 'fmt': '!H'}, # noqa: E501 MPTT-2 Operating Status: 0(Standby), 1(Work)
|
||||
0x42010030: {'reg': Register.BATT_PV1_VOLT, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, PV1 voltage
|
||||
0x42010032: {'reg': Register.BATT_PV1_CUR, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, PV1 current
|
||||
0x42010034: {'reg': Register.BATT_PV2_VOLT, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, PV2 voltage
|
||||
0x42010036: {'reg': Register.BATT_PV2_CUR, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, PV2 current
|
||||
0x42010038: {'reg': Register.BATT_38, 'fmt': '!h'}, # noqa: E501
|
||||
0x4201003a: {'reg': Register.BATT_TOTAL_GEN, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501
|
||||
0x4201003c: {'reg': Register.BATT_STATUS_1, 'fmt': '!h'}, # noqa: E501 MPTT-1 Status?
|
||||
0x4201003e: {'reg': Register.BATT_STATUS_2, 'fmt': '!h'}, # noqa: E501 MPTT-2 Status?
|
||||
0x42010040: {'reg': Register.BATT_VOLT, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501
|
||||
0x42010042: {'reg': Register.BATT_CUR, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501 => Batterie Status: <0(Discharging), 0(Static), 0>(Loading)
|
||||
0x42010042: {'reg': Register.BATT_CUR, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501
|
||||
0x42010044: {'reg': Register.BATT_SOC, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, state of charge (SOC) in percent
|
||||
0x42010046: {'reg': Register.BATT_CELL1_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x42010048: {'reg': Register.BATT_CELL2_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x4201004a: {'reg': Register.BATT_CELL3_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x4201004c: {'reg': Register.BATT_CELL4_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x4201004e: {'reg': Register.BATT_CELL5_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x42010050: {'reg': Register.BATT_CELL6_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x42010052: {'reg': Register.BATT_CELL7_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x42010054: {'reg': Register.BATT_CELL8_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x42010056: {'reg': Register.BATT_CELL9_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x42010058: {'reg': Register.BATT_CELL10_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x4201005a: {'reg': Register.BATT_CELL11_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x4201005c: {'reg': Register.BATT_CELL12_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x4201005e: {'reg': Register.BATT_CELL13_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x42010060: {'reg': Register.BATT_CELL14_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x42010062: {'reg': Register.BATT_CELL15_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x42010064: {'reg': Register.BATT_CELL16_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501H
|
||||
0x42010066: {'reg': Register.BATT_TEMP_1, 'fmt': '!h'}, # noqa: E501 Cell Temperture 1
|
||||
0x42010068: {'reg': Register.BATT_TEMP_2, 'fmt': '!h'}, # noqa: E501 Cell Temperture 2
|
||||
0x4201006a: {'reg': Register.BATT_TEMP_3, 'fmt': '!h'}, # noqa: E501 Cell Temperture 3
|
||||
0x4201006c: {'reg': Register.BATT_OUT_VOLT, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501 Output Voltage
|
||||
0x4201006e: {'reg': Register.BATT_OUT_CUR, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501 Output Current
|
||||
0x42010070: {'reg': Register.BATT_OUT_STATUS, 'fmt': '!H'}, # noqa: E501 Output Working Status: 0(Standby), 1(Work)
|
||||
0x42010072: {'reg': Register.BATT_TEMP_4, 'fmt': '!h'}, # noqa: E50, Environment temp
|
||||
0x42010074: {'reg': Register.BATT_ALARM, 'fmt': '!H'}, # noqa: E501 Warning Alarmcode 1, Bit 0..15
|
||||
0x42010076: {'reg': Register.BATT_HW_VERS, 'fmt': '!h'}, # noqa: E501 hardware version
|
||||
0x42010078: {'reg': Register.BATT_SW_VERS, 'fmt': '!h'}, # noqa: E501 software main version
|
||||
0x42010046: {'reg': Register.BATT_CELL1_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x42010048: {'reg': Register.BATT_CELL2_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x4201004a: {'reg': Register.BATT_CELL3_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x4201004c: {'reg': Register.BATT_CELL4_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x4201004e: {'reg': Register.BATT_CELL5_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x42010050: {'reg': Register.BATT_CELL6_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x42010052: {'reg': Register.BATT_CELL7_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x42010054: {'reg': Register.BATT_CELL8_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x42010056: {'reg': Register.BATT_CELL9_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x42010058: {'reg': Register.BATT_CELL10_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x4201005a: {'reg': Register.BATT_CELL11_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x4201005c: {'reg': Register.BATT_CELL12_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x4201005e: {'reg': Register.BATT_CELL13_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x42010060: {'reg': Register.BATT_CELL14_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x42010062: {'reg': Register.BATT_CELL15_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x42010064: {'reg': Register.BATT_CELL16_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
|
||||
0x42010066: {'reg': Register.BATT_TEMP_1, 'fmt': '!h'}, # noqa: E501
|
||||
0x42010068: {'reg': Register.BATT_TEMP_2, 'fmt': '!h'}, # noqa: E501
|
||||
0x4201006a: {'reg': Register.BATT_TEMP_3, 'fmt': '!h'}, # noqa: E501
|
||||
0x4201006c: {'reg': Register.BATT_OUT_VOLT, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501
|
||||
0x4201006e: {'reg': Register.BATT_OUT_CUR, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501
|
||||
0x42010070: {'reg': Register.BATT_OUT_STATUS, 'fmt': '!h'}, # noqa: E501, state of output value 0 or 1
|
||||
0x42010072: {'reg': Register.BATT_TEMP_4, 'fmt': '!h'}, # noqa: E501 controller temp
|
||||
0x42010074: {'reg': Register.BATT_74, 'fmt': '!h'}, # noqa: E501, control input 0..2048
|
||||
0x42010076: {'reg': Register.BATT_76, 'fmt': '!h'}, # noqa: E501
|
||||
0x42010078: {'reg': Register.BATT_78, 'fmt': '!h'}, # noqa: E501
|
||||
'calc': {
|
||||
1: {'reg': Register.BATT_PV_PWR, 'func': RegisterFunc.prod_sum, # noqa: E501 Generated Power
|
||||
1: {'reg': Register.BATT_PV_PWR, 'func': RegisterFunc.prod_sum, # noqa: E501
|
||||
'params': [[Register.BATT_PV1_VOLT, Register.BATT_PV1_CUR],
|
||||
[Register.BATT_PV2_VOLT, Register.BATT_PV2_CUR]]},
|
||||
2: {'reg': Register.BATT_PWR, 'func': RegisterFunc.prod_sum, # noqa: E501
|
||||
'params': [[Register.BATT_VOLT, Register.BATT_CUR]]},
|
||||
3: {'reg': Register.BATT_OUT_PWR, 'func': RegisterFunc.prod_sum, # noqa: E501 Supply Power => Power Supply State: 0(Idle), 0>(Power Supply)
|
||||
3: {'reg': Register.BATT_OUT_PWR, 'func': RegisterFunc.prod_sum, # noqa: E501
|
||||
'params': [[Register.BATT_OUT_VOLT, Register.BATT_OUT_CUR]]},
|
||||
4: {'reg': Register.BATT_PWR_SUPL_STATE, 'func': RegisterFunc.cmp_values, # noqa: E501
|
||||
'params': {'reg': Register.BATT_OUT_PWR, 'cmp_val': 0, 'res': [0, 0, 1]}}, # noqa: E501
|
||||
5: {'reg': Register.BATT_STATUS, 'func': RegisterFunc.cmp_values, # noqa: E501
|
||||
'params': {'reg': Register.BATT_CUR, 'cmp_val': 0.0, 'res': [0, 1, 2]}} # noqa: E501
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,7 +201,7 @@ class InfosG3P(Infos):
|
||||
self.set_db_def_value(Register.MANUFACTURER, 'TSUN')
|
||||
self.set_db_def_value(Register.EQUIPMENT_MODEL, 'TSOL-MSxx00')
|
||||
self.set_db_def_value(Register.CHIP_TYPE, 'IGEN TECH')
|
||||
self.set_db_def_value(Register.NO_INPUTS, 2)
|
||||
self.set_db_def_value(Register.NO_INPUTS, 4)
|
||||
|
||||
def __hide_topic(self, row: dict) -> bool:
|
||||
if 'dep' in row:
|
||||
|
||||
@@ -8,15 +8,6 @@ from gen3plus.solarman_emu import SolarmanEmu
|
||||
class InverterG3P(InverterBase):
|
||||
def __init__(self, reader: StreamReader, writer: StreamWriter,
|
||||
client_mode: bool = False):
|
||||
# shared value between both inverter connections
|
||||
self.forward_at_cmd_resp = False
|
||||
'''Flag if response for the last at command must be send to the cloud.
|
||||
|
||||
False: send result only to the MQTT broker, cause the AT+ command
|
||||
came from there
|
||||
True: send response packet to the cloud, cause the AT+ command
|
||||
came from the cloud'''
|
||||
|
||||
remote_prot = None
|
||||
if client_mode:
|
||||
remote_prot = SolarmanEmu
|
||||
|
||||
@@ -10,12 +10,11 @@ logger = logging.getLogger('msg')
|
||||
|
||||
|
||||
class SolarmanEmu(SolarmanBase):
|
||||
def __init__(self, inverter, addr, ifc: "AsyncIfc",
|
||||
def __init__(self, addr, ifc: "AsyncIfc",
|
||||
server_side: bool, client_mode: bool):
|
||||
super().__init__(addr, ifc, server_side=False,
|
||||
_send_modbus_cb=None,
|
||||
mb_timeout=8)
|
||||
_ = inverter
|
||||
logging.debug('SolarmanEmu.init()')
|
||||
self.db = ifc.remote.stream.db
|
||||
self.snr = ifc.remote.stream.snr
|
||||
|
||||
74
app/src/gen3plus/solarman_v5.py
Executable file → Normal file
@@ -247,20 +247,19 @@ class SolarmanBase(Message):
|
||||
class SolarmanV5(SolarmanBase):
|
||||
AT_CMD = 1
|
||||
MB_RTU_CMD = 2
|
||||
DCU_CMD = 5
|
||||
AT_CMD_RSP = 8
|
||||
MB_CLIENT_DATA_UP = 30
|
||||
'''Data up time in client mode'''
|
||||
HDR_FMT = '<BLLL'
|
||||
'''format string for packing of the header'''
|
||||
|
||||
def __init__(self, inverter, addr, ifc: "AsyncIfc",
|
||||
def __init__(self, addr, ifc: "AsyncIfc",
|
||||
server_side: bool, client_mode: bool):
|
||||
super().__init__(addr, ifc, server_side, self.send_modbus_cb,
|
||||
mb_timeout=8)
|
||||
|
||||
self.inverter = inverter
|
||||
self.db = InfosG3P(client_mode)
|
||||
self.forward_at_cmd_resp = False
|
||||
self.no_forwarding = False
|
||||
'''not allowed to connect to TSUN cloud by connection type'''
|
||||
self.establish_inv_emu = False
|
||||
@@ -327,7 +326,6 @@ class SolarmanV5(SolarmanBase):
|
||||
self.sensor_list = 0
|
||||
self.mb_regs = [{'addr': 0x3000, 'len': 48},
|
||||
{'addr': 0x2000, 'len': 96}]
|
||||
self.background_tasks = set()
|
||||
|
||||
'''
|
||||
Our puplic methods
|
||||
@@ -337,15 +335,13 @@ class SolarmanV5(SolarmanBase):
|
||||
# we have references to methods of this class in self.switch
|
||||
# so we have to erase self.switch, otherwise this instance can't be
|
||||
# deallocated by the garbage collector ==> we get a memory leak
|
||||
self.inverter = None
|
||||
self.switch.clear()
|
||||
self.log_lvl.clear()
|
||||
self.background_tasks.clear()
|
||||
super().close()
|
||||
|
||||
def send_start_cmd(self, snr: int, host: str,
|
||||
forward: bool,
|
||||
start_timeout=MB_CLIENT_DATA_UP):
|
||||
async def send_start_cmd(self, snr: int, host: str,
|
||||
forward: bool,
|
||||
start_timeout=MB_CLIENT_DATA_UP):
|
||||
self.no_forwarding = True
|
||||
self.establish_inv_emu = forward
|
||||
self.snr = snr
|
||||
@@ -396,7 +392,7 @@ class SolarmanV5(SolarmanBase):
|
||||
|
||||
def _set_config_parms(self, inv: dict, serial_no: str = ""):
|
||||
'''init connection with params from the configuration'''
|
||||
super()._set_config_parms(inv, serial_no)
|
||||
super()._set_config_parms(inv)
|
||||
snr = serial_no[:3]
|
||||
if '410' == snr:
|
||||
self.db.set_db_def_value(Register.EQUIPMENT_MODEL,
|
||||
@@ -523,7 +519,7 @@ class SolarmanV5(SolarmanBase):
|
||||
await Proxy.mqtt.publish(f'{Proxy.entity_prfx}{node_id}{key}', data_json) # noqa: E501
|
||||
return
|
||||
|
||||
self.inverter.forward_at_cmd_resp = False
|
||||
self.forward_at_cmd_resp = False
|
||||
self._build_header(0x4510)
|
||||
self.ifc.tx_add(struct.pack(f'<BHLLL{len(at_cmd)}sc', self.AT_CMD,
|
||||
0x0002, 0, 0, 0,
|
||||
@@ -535,26 +531,6 @@ class SolarmanV5(SolarmanBase):
|
||||
except Exception:
|
||||
self.ifc.tx_clear()
|
||||
|
||||
def send_dcu_cmd(self, pdu: bytearray):
|
||||
if self.sensor_list != 0x3026:
|
||||
logger.debug(f'[{self.node_id}] DCU CMD not allowed,'
|
||||
f' for sensor: {self.sensor_list:#04x}')
|
||||
return
|
||||
|
||||
if self.state != State.up:
|
||||
logger.warning(f'[{self.node_id}] ignore DCU CMD,'
|
||||
' cause the state is not UP anymore')
|
||||
return
|
||||
|
||||
self.inverter.forward_dcu_cmd_resp = False
|
||||
self._build_header(0x4510)
|
||||
self.ifc.tx_add(struct.pack('<BHLLL', self.DCU_CMD,
|
||||
self.sensor_list, 0, 0, 0))
|
||||
self.ifc.tx_add(pdu)
|
||||
self._finish_send_msg()
|
||||
self.ifc.tx_log(logging.INFO, f'Send DCU CMD :{self.addr}:')
|
||||
self.ifc.tx_flush()
|
||||
|
||||
def __forward_msg(self):
|
||||
self.forward(self.ifc.rx_peek(), self.header_len+self.data_len+2)
|
||||
|
||||
@@ -564,17 +540,12 @@ class SolarmanV5(SolarmanBase):
|
||||
rated = db.get_db_value(Register.RATED_POWER, 0)
|
||||
model = None
|
||||
if max_pow == 2000:
|
||||
db.set_db_def_value(Register.NO_INPUTS, 4)
|
||||
if rated == 800 or rated == 600:
|
||||
model = f'TSOL-MS{max_pow}({rated})'
|
||||
else:
|
||||
model = f'TSOL-MS{max_pow}'
|
||||
elif max_pow == 1800 or max_pow == 1600:
|
||||
db.set_db_def_value(Register.NO_INPUTS, 4)
|
||||
model = f'TSOL-MS{max_pow}'
|
||||
elif max_pow <= 800:
|
||||
model = f'TSOL-MS{max_pow}'
|
||||
|
||||
if model:
|
||||
logger.info(f'Model: {model}')
|
||||
self.db.set_db_def_value(Register.EQUIPMENT_MODEL, model)
|
||||
@@ -673,11 +644,7 @@ class SolarmanV5(SolarmanBase):
|
||||
self.inc_counter('AT_Command_Blocked')
|
||||
return
|
||||
self.inc_counter('AT_Command')
|
||||
self.inverter.forward_at_cmd_resp = True
|
||||
|
||||
if ftype == self.DCU_CMD:
|
||||
self.inc_counter('DCU_Command')
|
||||
self.inverter.forward_dcu_cmd_resp = True
|
||||
self.forward_at_cmd_resp = True
|
||||
|
||||
elif ftype == self.MB_RTU_CMD:
|
||||
rstream = self.ifc.remote.stream
|
||||
@@ -692,20 +659,13 @@ class SolarmanV5(SolarmanBase):
|
||||
self.__forward_msg()
|
||||
|
||||
def publish_mqtt(self, key, data): # pragma: no cover
|
||||
task = asyncio.ensure_future(
|
||||
asyncio.ensure_future(
|
||||
Proxy.mqtt.publish(key, data))
|
||||
self.background_tasks.add(task)
|
||||
task.add_done_callback(self.background_tasks.discard)
|
||||
|
||||
def get_cmd_rsp_log_lvl(self) -> int:
|
||||
ftype = self.ifc.rx_peek()[self.header_len]
|
||||
if ftype == self.AT_CMD or \
|
||||
ftype == self.AT_CMD_RSP:
|
||||
if self.inverter.forward_at_cmd_resp:
|
||||
return logging.INFO
|
||||
return logging.DEBUG
|
||||
elif ftype == self.DCU_CMD:
|
||||
if self.inverter.forward_dcu_cmd_resp:
|
||||
if ftype == self.AT_CMD:
|
||||
if self.forward_at_cmd_resp:
|
||||
return logging.INFO
|
||||
return logging.DEBUG
|
||||
elif ftype == self.MB_RTU_CMD \
|
||||
@@ -720,23 +680,13 @@ class SolarmanV5(SolarmanBase):
|
||||
ftype = data[0]
|
||||
if ftype == self.AT_CMD or \
|
||||
ftype == self.AT_CMD_RSP:
|
||||
if not self.inverter.forward_at_cmd_resp:
|
||||
if not self.forward_at_cmd_resp:
|
||||
data_json = data[14:].decode("utf-8")
|
||||
node_id = self.node_id
|
||||
key = 'at_resp'
|
||||
logger.info(f'{key}: {data_json}')
|
||||
self.publish_mqtt(f'{Proxy.entity_prfx}{node_id}{key}', data_json) # noqa: E501
|
||||
return
|
||||
|
||||
elif ftype == self.DCU_CMD:
|
||||
if not self.inverter.forward_dcu_cmd_resp:
|
||||
data_json = '+ok'
|
||||
node_id = self.node_id
|
||||
key = 'dcu_resp'
|
||||
logger.info(f'{key}: {data_json}')
|
||||
self.publish_mqtt(f'{Proxy.entity_prfx}{node_id}{key}', data_json) # noqa: E501
|
||||
return
|
||||
|
||||
elif ftype == self.MB_RTU_CMD:
|
||||
self.__modbus_command_rsp(data)
|
||||
return
|
||||
|
||||
248
app/src/infos.py
@@ -44,7 +44,6 @@ class Register(Enum):
|
||||
MODBUS_COMMAND = 60
|
||||
AT_COMMAND_BLOCKED = 61
|
||||
CLOUD_CONN_CNT = 62
|
||||
DCU_COMMAND = 63
|
||||
OUTPUT_POWER = 83
|
||||
RATED_POWER = 84
|
||||
INVERTER_TEMP = 85
|
||||
@@ -126,9 +125,10 @@ class Register(Enum):
|
||||
BATT_PV1_CUR = 1001
|
||||
BATT_PV2_VOLT = 1002
|
||||
BATT_PV2_CUR = 1003
|
||||
BATT_TOTAL_CHARG = 1005
|
||||
BATT_PV1_STATUS = 1006
|
||||
BATT_PV2_STATUS = 1007
|
||||
BATT_38 = 1004
|
||||
BATT_TOTAL_GEN = 1005
|
||||
BATT_STATUS_1 = 1006
|
||||
BATT_STATUS_2 = 1007
|
||||
BATT_VOLT = 1010
|
||||
BATT_CUR = 1011
|
||||
BATT_SOC = 1012
|
||||
@@ -155,14 +155,12 @@ class Register(Enum):
|
||||
BATT_OUT_CUR = 1033
|
||||
BATT_OUT_STATUS = 1034
|
||||
BATT_TEMP_4 = 1035
|
||||
BATT_ALARM = 1036
|
||||
BATT_HW_VERS = 1037
|
||||
BATT_SW_VERS = 1038
|
||||
BATT_74 = 1036
|
||||
BATT_76 = 1037
|
||||
BATT_78 = 1038
|
||||
BATT_PV_PWR = 1040
|
||||
BATT_PWR = 1041
|
||||
BATT_OUT_PWR = 1042
|
||||
BATT_PWR_SUPL_STATE = 1043
|
||||
BATT_STATUS = 1044
|
||||
|
||||
TEST_VAL_0 = 2000
|
||||
TEST_VAL_1 = 2001
|
||||
@@ -327,11 +325,9 @@ class Infos:
|
||||
SOLAR_POWER_VAR = 'mdi:solar-power-variant'
|
||||
SOLAR_POWER = 'mdi:solar-power'
|
||||
WIFI = 'mdi:wifi'
|
||||
ALARM_LIGHT = 'mdi:alarm-light'
|
||||
UPDATE = 'mdi:update'
|
||||
DAILY_GEN = 'Daily Generation'
|
||||
TOTAL_GEN = 'Total Generation'
|
||||
TOTAL_CHARG = 'Total Charging Energy'
|
||||
FMT_INT = '| int'
|
||||
FMT_FLOAT = '| float'
|
||||
FMT_STRING_SEC = '| string + " s"'
|
||||
@@ -371,7 +367,7 @@ class Infos:
|
||||
'input_pv5': {'via': 'inverter', 'name': 'Module PV5', 'mdl': Register.PV5_MODEL, 'mf': Register.PV5_MANUFACTURER, 'dep': {'reg': Register.NO_INPUTS, 'gte': 5}}, # noqa: E501
|
||||
'input_pv6': {'via': 'inverter', 'name': 'Module PV6', 'mdl': Register.PV6_MODEL, 'mf': Register.PV6_MANUFACTURER, 'dep': {'reg': Register.NO_INPUTS, 'gte': 6}}, # noqa: E501
|
||||
|
||||
'batterie': {'via': 'controller', 'name': 'Batterie', 'mdl': Register.EQUIPMENT_MODEL, 'mf': Register.MANUFACTURER, 'hw': Register.BATT_HW_VERS, 'sw': Register.BATT_SW_VERS, 'sn': Register.SERIAL_NUMBER}, # noqa: E501
|
||||
'batterie': {'via': 'controller', 'name': 'Batterie', 'mdl': Register.EQUIPMENT_MODEL, 'mf': Register.MANUFACTURER, 'sw': Register.VERSION, 'sn': Register.SERIAL_NUMBER}, # noqa: E501
|
||||
'bat_inp_pv1': {'via': 'batterie', 'name': 'Module PV1', 'mdl': Register.PV1_MODEL, 'mf': Register.PV1_MANUFACTURER}, # noqa: E501
|
||||
'bat_inp_pv2': {'via': 'batterie', 'name': 'Module PV2', 'mdl': Register.PV2_MODEL, 'mf': Register.PV2_MANUFACTURER}, # noqa: E501
|
||||
}
|
||||
@@ -379,11 +375,9 @@ class Infos:
|
||||
__comm_type_val_tpl = "{%set com_types = ['n/a','Wi-Fi', 'G4', 'G5', 'GPRS'] %}{{com_types[value_json['Communication_Type']|int(0)]|default(value_json['Communication_Type'])}}" # noqa: E501
|
||||
__work_mode_val_tpl = "{%set mode = ['Normal-Mode', 'Aging-Mode', 'ATE-Mode', 'Shielding GFDI', 'DTU-Mode'] %}{{mode[value_json['Work_Mode']|int(0)]|default(value_json['Work_Mode'])}}" # noqa: E501
|
||||
__status_type_val_tpl = "{%set inv_status = ['Off-line', 'On-grid', 'Off-grid'] %}{{inv_status[value_json['Inverter_Status']|int(0)]|default(value_json['Inverter_Status'])}}" # noqa: E501
|
||||
__mppt1_status_type_val_tpl = "{%set mppt_status = ['Standby', 'On', 'Off'] %}{{mppt_status[value_json['pv1']['MPPT-Status']|int(0)]|default(value_json['pv1']['MPPT-Status'])}}" # noqa: E501
|
||||
__mppt2_status_type_val_tpl = "{%set mppt_status = ['Standby', 'On', 'Off'] %}{{mppt_status[value_json['pv2']['MPPT-Status']|int(0)]|default(value_json['pv2']['MPPT-Status'])}}" # noqa: E501
|
||||
__supply_status_type_val_tpl = "{%set supply_status = ['Idle', 'Power-Supply'] %}{{supply_status[value_json['out']['Suppl_State']|int(0)]|default(value_json['out']['Suppl_State'])}}" # noqa: E501
|
||||
__batt_status_type_val_tpl = "{%set batt_status = ['Discharging', 'Static', 'Loading'] %}{{batt_status[value_json['batt']['Batt_State']|int(0)]|default(value_json['batt']['Batt_State'])}}" # noqa: E501
|
||||
__out_status_type_val_tpl = "{%set out_status = ['Standby', 'On', 'Off'] %}{{out_status[value_json['out']['Out_Status']|int(0)]|default(value_json['out']['Out_Status'])}}" # noqa: E501
|
||||
__mppt1_status_type_val_tpl = "{%set mppt_status = ['Locked', 'On', 'Off'] %}{{mppt_status[value_json['Status_1']|int(0)]|default(value_json['Status_1'])}}" # noqa: E501
|
||||
__mppt2_status_type_val_tpl = "{%set mppt_status = ['Locked', 'On', 'Off'] %}{{mppt_status[value_json['Status_2']|int(0)]|default(value_json['Status_2'])}}" # noqa: E501
|
||||
__out_status_type_val_tpl = "{%set out_status = ['Off', 'On'] %}{{out_status[value_json['out']['Out_Status']|int(0)]|default(value_json['out']['Out_Status'])}}" # noqa: E501
|
||||
__rated_power_val_tpl = "{% if 'Rated_Power' in value_json and value_json['Rated_Power'] != None %}{{value_json['Rated_Power']|string() +' W'}}{% else %}{{ this.state }}{% endif %}" # noqa: E501
|
||||
__designed_power_val_tpl = '''
|
||||
{% if 'Max_Designed_Power' in value_json and
|
||||
@@ -405,52 +399,52 @@ class Infos:
|
||||
{% set result = 'noAlarm'%}
|
||||
{%else%}
|
||||
{% set result = '' %}
|
||||
{% if val_int | bitwise_and(0x0001)%}
|
||||
{% if val_int | bitwise_and(1)%}
|
||||
{% set result = result + 'HBridgeFault, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0002)%}
|
||||
{% if val_int | bitwise_and(2)%}
|
||||
{% set result = result + 'DriVoltageFault, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0004)%}
|
||||
{% if val_int | bitwise_and(3)%}
|
||||
{% set result = result + 'GFDI-Fault, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0008)%}
|
||||
{% if val_int | bitwise_and(4)%}
|
||||
{% set result = result + 'OverTemp, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0010)%}
|
||||
{% if val_int | bitwise_and(5)%}
|
||||
{% set result = result + 'CommLose, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0020)%}
|
||||
{% if val_int | bitwise_and(6)%}
|
||||
{% set result = result + 'Bit6, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0040)%}
|
||||
{% if val_int | bitwise_and(7)%}
|
||||
{% set result = result + 'Bit7, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0080)%}
|
||||
{% if val_int | bitwise_and(8)%}
|
||||
{% set result = result + 'EEPROM-Fault, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0100)%}
|
||||
{% if val_int | bitwise_and(9)%}
|
||||
{% set result = result + 'NoUtility, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0200)%}
|
||||
{% if val_int | bitwise_and(10)%}
|
||||
{% set result = result + 'VG_Offset, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0400)%}
|
||||
{% if val_int | bitwise_and(11)%}
|
||||
{% set result = result + 'Relais_Open, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0800)%}
|
||||
{% if val_int | bitwise_and(12)%}
|
||||
{% set result = result + 'Relais_Short, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x1000)%}
|
||||
{% if val_int | bitwise_and(13)%}
|
||||
{% set result = result + 'GridVoltOverRating, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x2000)%}
|
||||
{% if val_int | bitwise_and(14)%}
|
||||
{% set result = result + 'GridVoltUnderRating, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x4000)%}
|
||||
{% if val_int | bitwise_and(15)%}
|
||||
{% set result = result + 'GridFreqOverRating, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x8000)%}
|
||||
{% if val_int | bitwise_and(16)%}
|
||||
{% set result = result + 'GridFreqUnderRating, '%}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -467,104 +461,42 @@ class Infos:
|
||||
{% set result = 'noFault'%}
|
||||
{%else%}
|
||||
{% set result = '' %}
|
||||
{% if val_int | bitwise_and(0x0001)%}
|
||||
{% if val_int | bitwise_and(1)%}
|
||||
{% set result = result + 'PVOV-Fault (PV OverVolt), '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0002)%}
|
||||
{% if val_int | bitwise_and(2)%}
|
||||
{% set result = result + 'PVLV-Fault (PV LowVolt), '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0004)%}
|
||||
{% if val_int | bitwise_and(3)%}
|
||||
{% set result = result + 'PV OI-Fault (PV OverCurrent), '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0008)%}
|
||||
{% if val_int | bitwise_and(4)%}
|
||||
{% set result = result + 'PV OFV-Fault, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0010)%}
|
||||
{% if val_int | bitwise_and(5)%}
|
||||
{% set result = result + 'DC ShortCircuitFault, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0020)%}{% set result = result + 'Bit6, '%}
|
||||
{% if val_int | bitwise_and(6)%}{% set result = result + 'Bit6, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0040)%}{% set result = result + 'Bit7, '%}
|
||||
{% if val_int | bitwise_and(7)%}{% set result = result + 'Bit7, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0080)%}{% set result = result + 'Bit8, '%}
|
||||
{% if val_int | bitwise_and(8)%}{% set result = result + 'Bit8, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0100)%}{% set result = result + 'Bit9, '%}
|
||||
{% if val_int | bitwise_and(9)%}{% set result = result + 'Bit9, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0200)%}{% set result = result + 'Bit10, '%}
|
||||
{% if val_int | bitwise_and(10)%}{% set result = result + 'Bit10, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0400)%}{% set result = result + 'Bit11, '%}
|
||||
{% if val_int | bitwise_and(11)%}{% set result = result + 'Bit11, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0800)%}{% set result = result + 'Bit12, '%}
|
||||
{% if val_int | bitwise_and(12)%}{% set result = result + 'Bit12, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x1000)%}{% set result = result + 'Bit13, '%}
|
||||
{% if val_int | bitwise_and(13)%}{% set result = result + 'Bit13, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x2000)%}{% set result = result + 'Bit14, '%}
|
||||
{% if val_int | bitwise_and(14)%}{% set result = result + 'Bit14, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x4000)%}{% set result = result + 'Bit15, '%}
|
||||
{% if val_int | bitwise_and(15)%}{% set result = result + 'Bit15, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x8000)%}{% set result = result + 'Bit16, '%}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{{ result }}
|
||||
{% else %}
|
||||
{{ this.state }}
|
||||
{% endif %}
|
||||
'''
|
||||
__batt_alarm_val_tpl = '''
|
||||
{% if 'Batterie_Alarm' in value_json and
|
||||
value_json['Batterie_Alarm'] != None %}
|
||||
{% set val_int = value_json['Batterie_Alarm'] | int %}
|
||||
{% if val_int == 0 %}
|
||||
{% set result = 'noAlarm'%}
|
||||
{%else%}
|
||||
{% set result = '' %}
|
||||
{% if val_int | bitwise_and(0x0001)%}
|
||||
{% set result = result + 'PV1-OverVoltage, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0002)%}
|
||||
{% set result = result + 'PV2-OverVoltage, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0004)%}
|
||||
{% set result = result + 'EquipmentOverheating, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0008)%}
|
||||
{% set result = result + 'EquipmentLowTemp, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0010)%}
|
||||
{% set result = result + 'BMS-CommFailed, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0020)%}
|
||||
{% set result = result + 'UnderVoltageProt, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0040)%}
|
||||
{% set result = result + 'ChargingHighTemp, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0080)%}
|
||||
{% set result = result + 'ChargingLowTemp, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0100)%}
|
||||
{% set result = result + 'DischargeHighTemp, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0200)%}
|
||||
{% set result = result + 'DischargeLowTemp, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0400)%}
|
||||
{% set result = result + 'BatterieOverVoltage, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x0800)%}
|
||||
{% set result = result + 'SingleCorePressureDifferenceIsTooLarge, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x1000)%}
|
||||
{% set result = result + 'Bit-12, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x2000)%}
|
||||
{% set result = result + 'Bit-13, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x4000)%}
|
||||
{% set result = result + 'Bit-14, '%}
|
||||
{% endif %}
|
||||
{% if val_int | bitwise_and(0x8000)%}
|
||||
{% set result = result + 'Bit-15, '%}
|
||||
{% if val_int | bitwise_and(16)%}{% set result = result + 'Bit16, '%}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{{ result }}
|
||||
@@ -626,13 +558,12 @@ class Infos:
|
||||
Register.INVALID_MSG_FMT: {'name': ['proxy', 'Invalid_Msg_Format'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'inv_msg_fmt_', 'fmt': FMT_INT, 'name': 'Invalid Message Format', 'icon': COUNTER, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.AT_COMMAND: {'name': ['proxy', 'AT_Command'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'at_cmd_', 'fmt': FMT_INT, 'name': 'AT Command', 'icon': COUNTER, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.AT_COMMAND_BLOCKED: {'name': ['proxy', 'AT_Command_Blocked'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'at_cmd_blocked_', 'fmt': FMT_INT, 'name': 'AT Command Blocked', 'icon': COUNTER, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.DCU_COMMAND: {'name': ['proxy', 'DCU_Command'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'dcu_cmd_', 'fmt': FMT_INT, 'name': 'DCU Command', 'icon': COUNTER, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.MODBUS_COMMAND: {'name': ['proxy', 'Modbus_Command'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'modbus_cmd_', 'fmt': FMT_INT, 'name': 'Modbus Command', 'icon': COUNTER, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
# 0xffffff03: {'name':['proxy', 'Voltage'], 'level': logging.DEBUG, 'unit': 'V', 'ha':{'dev':'proxy', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id':'proxy_volt_', 'fmt':FMT_FLOAT,'name': 'Grid Voltage'}}, # noqa: E501
|
||||
|
||||
# events
|
||||
Register.EVENT_ALARM: {'name': ['events', 'Inverter_Alarm'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'inverter', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'inv_alarm_', 'name': 'Inverter Alarm', 'val_tpl': __inv_alarm_val_tpl, 'icon': ALARM_LIGHT}}, # noqa: E501
|
||||
Register.EVENT_FAULT: {'name': ['events', 'Inverter_Fault'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'inverter', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'inv_fault_', 'name': 'Inverter Fault', 'val_tpl': __inv_fault_val_tpl, 'icon': ALARM_LIGHT}}, # noqa: E501
|
||||
Register.EVENT_ALARM: {'name': ['events', 'Inverter_Alarm'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'inverter', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'inv_alarm_', 'name': 'Inverter Alarm', 'val_tpl': __inv_alarm_val_tpl, 'icon': 'mdi:alarm-light'}}, # noqa: E501
|
||||
Register.EVENT_FAULT: {'name': ['events', 'Inverter_Fault'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'inverter', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'inv_fault_', 'name': 'Inverter Fault', 'val_tpl': __inv_fault_val_tpl, 'icon': 'mdi:alarm-light'}}, # noqa: E501
|
||||
Register.EVENT_BF1: {'name': ['events', 'Inverter_Bitfield_1'], 'level': logging.INFO, 'unit': ''}, # noqa: E501
|
||||
Register.EVENT_BF2: {'name': ['events', 'Inverter_bitfield_2'], 'level': logging.INFO, 'unit': ''}, # noqa: E501
|
||||
# Register.EVENT_409: {'name': ['events', '409_No_Utility'], 'level': logging.DEBUG, 'unit': ''}, # noqa: E501
|
||||
@@ -705,53 +636,46 @@ class Infos:
|
||||
Register.PROD_COMPL_TYPE: {'name': ['other', 'Prod_Compliance_Type'], 'level': logging.INFO, 'unit': ''}, # noqa: E501
|
||||
Register.INV_UNKNOWN_1: {'name': ['inv_unknown', 'Unknown_1'], 'level': logging.DEBUG, 'unit': ''}, # noqa: E501
|
||||
|
||||
# Batterie DC-1000: Electricity Genration
|
||||
Register.BATT_PV1_STATUS: {'name': ['batterie', 'pv1', 'MPPT-Status'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'status1_', 'name': 'MPPT-1 Status', 'val_tpl': __mppt1_status_type_val_tpl, 'icon': POWER}}, # noqa: E501
|
||||
Register.BATT_PV1_VOLT: {'name': ['batterie', 'pv1', 'Voltage'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'bat_inp_pv1', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_pv1_', 'val_tpl': "{{ (value_json['pv1']['Voltage'] | float)}}", 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_PV1_CUR: {'name': ['batterie', 'pv1', 'Current'], 'level': logging.INFO, 'unit': 'A', 'ha': {'dev': 'bat_inp_pv1', 'dev_cla': 'current', 'stat_cla': 'measurement', 'id': 'cur_pv1_', 'val_tpl': "{{ (value_json['pv1']['Current'] | float)}}", 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_PV2_STATUS: {'name': ['batterie', 'pv2', 'MPPT-Status'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'status2_', 'name': 'MPPT-2 Status', 'val_tpl': __mppt2_status_type_val_tpl, 'icon': POWER}}, # noqa: E501
|
||||
Register.BATT_PV2_VOLT: {'name': ['batterie', 'pv2', 'Voltage'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'bat_inp_pv2', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_pv2_', 'val_tpl': "{{ (value_json['pv2']['Voltage'] | float)}}", 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_PV2_CUR: {'name': ['batterie', 'pv2', 'Current'], 'level': logging.INFO, 'unit': 'A', 'ha': {'dev': 'bat_inp_pv2', 'dev_cla': 'current', 'stat_cla': 'measurement', 'id': 'cur_pv2_', 'val_tpl': "{{ (value_json['pv2']['Current'] | float)}}", 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_PV_PWR: {'name': ['batterie', 'PV_Power'], 'level': logging.INFO, 'unit': 'W', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'pv_power_', 'fmt': FMT_INT, 'name': 'PV Power'}}, # noqa: E501
|
||||
Register.BATT_OUT_STATUS: {'name': ['batterie', 'out', 'Out_Status'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'out_status_', 'name': 'Output Status', 'val_tpl': __out_status_type_val_tpl, 'icon': POWER}}, # noqa: E501
|
||||
Register.BATT_38: {'name': ['batterie', 'Reg_38'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_38_', 'fmt': FMT_FLOAT, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_TOTAL_GEN: {'name': ['batterie', 'Total_Generation'], 'level': logging.INFO, 'unit': 'kWh', 'ha': {'dev': 'batterie', 'dev_cla': 'energy', 'stat_cla': 'total', 'id': 'total_gen_', 'fmt': FMT_FLOAT, 'name': TOTAL_GEN, 'icon': SOLAR_POWER, 'must_incr': True}}, # noqa: E501
|
||||
Register.BATT_STATUS_1: {'name': ['batterie', 'Status_1'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'status1_', 'name': 'MPPT-1 Status', 'val_tpl': __mppt1_status_type_val_tpl, 'icon': POWER}}, # noqa: E501
|
||||
Register.BATT_STATUS_2: {'name': ['batterie', 'Status_2'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'status2_', 'name': 'MPPT-2 Status', 'val_tpl': __mppt2_status_type_val_tpl, 'icon': POWER}}, # noqa: E501
|
||||
Register.BATT_VOLT: {'name': ['batterie', 'Voltage'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_bat_', 'fmt': FMT_FLOAT, 'name': 'Batterie Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CUR: {'name': ['batterie', 'Current'], 'level': logging.INFO, 'unit': 'A', 'ha': {'dev': 'batterie', 'dev_cla': 'current', 'stat_cla': 'measurement', 'id': 'cur_bat_', 'fmt': FMT_FLOAT, 'name': 'Batterie Current', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_SOC: {'name': ['batterie', 'SOC'], 'level': logging.INFO, 'unit': '%', 'ha': {'dev': 'batterie', 'dev_cla': None, 'stat_cla': 'measurement', 'id': 'soc_', 'fmt': FMT_FLOAT, 'name': 'State of Charge (SOC)', 'icon': 'mdi:battery-90'}}, # noqa: E501
|
||||
Register.BATT_CELL1_VOLT: {'name': ['batterie', 'Cell', 'Volt1'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell1_', 'val_tpl': "{{ (value_json['Cell']['Volt1'] | float)}}", 'name': 'Cell-01 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL3_VOLT: {'name': ['batterie', 'Cell', 'Volt3'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell3_', 'val_tpl': "{{ (value_json['Cell']['Volt2'] | float)}}", 'name': 'Cell-03 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL4_VOLT: {'name': ['batterie', 'Cell', 'Volt4'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell4_', 'val_tpl': "{{ (value_json['Cell']['Volt3'] | float)}}", 'name': 'Cell-04 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL2_VOLT: {'name': ['batterie', 'Cell', 'Volt2'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell2_', 'val_tpl': "{{ (value_json['Cell']['Volt4'] | float)}}", 'name': 'Cell-02 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL5_VOLT: {'name': ['batterie', 'Cell', 'Volt5'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell5_', 'val_tpl': "{{ (value_json['Cell']['Volt5'] | float)}}", 'name': 'Cell-05 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL6_VOLT: {'name': ['batterie', 'Cell', 'Volt6'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell6_', 'val_tpl': "{{ (value_json['Cell']['Volt6'] | float)}}", 'name': 'Cell-06 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL7_VOLT: {'name': ['batterie', 'Cell', 'Volt7'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell7_', 'val_tpl': "{{ (value_json['Cell']['Volt7'] | float)}}", 'name': 'Cell-07 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL8_VOLT: {'name': ['batterie', 'Cell', 'Volt8'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell8_', 'val_tpl': "{{ (value_json['Cell']['Volt8'] | float)}}", 'name': 'Cell-08 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL9_VOLT: {'name': ['batterie', 'Cell', 'Volt9'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell9_', 'val_tpl': "{{ (value_json['Cell']['Volt9'] | float)}}", 'name': 'Cell-09 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL10_VOLT: {'name': ['batterie', 'Cell', 'Volt10'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell10_', 'val_tpl': "{{ (value_json['Cell']['Volt10'] | float)}}", 'name': 'Cell-10 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL11_VOLT: {'name': ['batterie', 'Cell', 'Volt11'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell11_', 'val_tpl': "{{ (value_json['Cell']['Volt11'] | float)}}", 'name': 'Cell-11 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL12_VOLT: {'name': ['batterie', 'Cell', 'Volt12'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell12_', 'val_tpl': "{{ (value_json['Cell']['Volt12'] | float)}}", 'name': 'Cell-12 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL13_VOLT: {'name': ['batterie', 'Cell', 'Volt13'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell13_', 'val_tpl': "{{ (value_json['Cell']['Volt13'] | float)}}", 'name': 'Cell-13 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL14_VOLT: {'name': ['batterie', 'Cell', 'Volt14'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell14_', 'val_tpl': "{{ (value_json['Cell']['Volt14'] | float)}}", 'name': 'Cell-14 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL15_VOLT: {'name': ['batterie', 'Cell', 'Volt15'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell15_', 'val_tpl': "{{ (value_json['Cell']['Volt15'] | float)}}", 'name': 'Cell-15 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL16_VOLT: {'name': ['batterie', 'Cell', 'Volt16'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell16_', 'val_tpl': "{{ (value_json['Cell']['Volt16'] | float)}}", 'name': 'Cell-16 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_TEMP_1: {'name': ['batterie', 'Temp_1'], 'level': logging.INFO, 'unit': '°C', 'ha': {'dev': 'batterie', 'dev_cla': 'temperature', 'stat_cla': 'measurement', 'id': 'temp_1_', 'fmt': FMT_INT, 'name': 'Batterie Temp-1', 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_TEMP_2: {'name': ['batterie', 'Temp_2'], 'level': logging.INFO, 'unit': '°C', 'ha': {'dev': 'batterie', 'dev_cla': 'temperature', 'stat_cla': 'measurement', 'id': 'temp_2_', 'fmt': FMT_INT, 'name': 'Batterie Temp-2', 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_TEMP_3: {'name': ['batterie', 'Temp_3'], 'level': logging.INFO, 'unit': '°C', 'ha': {'dev': 'batterie', 'dev_cla': 'temperature', 'stat_cla': 'measurement', 'id': 'temp_3_', 'fmt': FMT_INT, 'name': 'Batterie Temp-3', 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_OUT_VOLT: {'name': ['batterie', 'out', 'Voltage'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'out_volt_', 'val_tpl': "{{ (value_json['out']['Voltage'] | float)}}", 'name': 'Output Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_OUT_CUR: {'name': ['batterie', 'out', 'Current'], 'level': logging.INFO, 'unit': 'A', 'ha': {'dev': 'batterie', 'dev_cla': 'current', 'stat_cla': 'measurement', 'id': 'out_cur_', 'val_tpl': "{{ (value_json['out']['Current'] | float)}}", 'name': 'Output Current', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_OUT_PWR: {'name': ['batterie', 'out', 'Power'], 'level': logging.INFO, 'unit': 'W', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'out_power_', 'val_tpl': "{{ (value_json['out']['Power'] | int)}}", 'name': 'Supply Power'}}, # noqa: E501
|
||||
Register.BATT_PWR_SUPL_STATE: {'name': ['batterie', 'out', 'Suppl_State'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'status_supply_', 'name': 'Supply State', 'val_tpl': __supply_status_type_val_tpl, 'icon': POWER}}, # noqa: E501
|
||||
|
||||
# Batterie DC-1000: Cell Package
|
||||
Register.BATT_CELL1_VOLT: {'name': ['batterie', 'cell', 'Volt1'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell1_', 'val_tpl': "{{ (value_json['cell']['Volt1'] | float)}}", 'name': 'Cell-01 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL3_VOLT: {'name': ['batterie', 'cell', 'Volt3'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell3_', 'val_tpl': "{{ (value_json['cell']['Volt2'] | float)}}", 'name': 'Cell-03 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL4_VOLT: {'name': ['batterie', 'cell', 'Volt4'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell4_', 'val_tpl': "{{ (value_json['cell']['Volt3'] | float)}}", 'name': 'Cell-04 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL2_VOLT: {'name': ['batterie', 'cell', 'Volt2'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell2_', 'val_tpl': "{{ (value_json['cell']['Volt4'] | float)}}", 'name': 'Cell-02 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL5_VOLT: {'name': ['batterie', 'cell', 'Volt5'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell5_', 'val_tpl': "{{ (value_json['cell']['Volt5'] | float)}}", 'name': 'Cell-05 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL6_VOLT: {'name': ['batterie', 'cell', 'Volt6'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell6_', 'val_tpl': "{{ (value_json['cell']['Volt6'] | float)}}", 'name': 'Cell-06 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL7_VOLT: {'name': ['batterie', 'cell', 'Volt7'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell7_', 'val_tpl': "{{ (value_json['cell']['Volt7'] | float)}}", 'name': 'Cell-07 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL8_VOLT: {'name': ['batterie', 'cell', 'Volt8'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell8_', 'val_tpl': "{{ (value_json['cell']['Volt8'] | float)}}", 'name': 'Cell-08 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL9_VOLT: {'name': ['batterie', 'cell', 'Volt9'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell9_', 'val_tpl': "{{ (value_json['cell']['Volt9'] | float)}}", 'name': 'Cell-09 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL10_VOLT: {'name': ['batterie', 'cell', 'Volt10'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell10_', 'val_tpl': "{{ (value_json['cell']['Volt10'] | float)}}", 'name': 'Cell-10 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL11_VOLT: {'name': ['batterie', 'cell', 'Volt11'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell11_', 'val_tpl': "{{ (value_json['cell']['Volt11'] | float)}}", 'name': 'Cell-11 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL12_VOLT: {'name': ['batterie', 'cell', 'Volt12'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell12_', 'val_tpl': "{{ (value_json['cell']['Volt12'] | float)}}", 'name': 'Cell-12 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL13_VOLT: {'name': ['batterie', 'cell', 'Volt13'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell13_', 'val_tpl': "{{ (value_json['cell']['Volt13'] | float)}}", 'name': 'Cell-13 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL14_VOLT: {'name': ['batterie', 'cell', 'Volt14'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell14_', 'val_tpl': "{{ (value_json['cell']['Volt14'] | float)}}", 'name': 'Cell-14 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL15_VOLT: {'name': ['batterie', 'cell', 'Volt15'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell15_', 'val_tpl': "{{ (value_json['cell']['Volt15'] | float)}}", 'name': 'Cell-15 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CELL16_VOLT: {'name': ['batterie', 'cell', 'Volt16'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_cell16_', 'val_tpl': "{{ (value_json['cell']['Volt16'] | float)}}", 'name': 'Cell-16 Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
|
||||
# Batterie DC-1000: Batterie Pack
|
||||
Register.BATT_VOLT: {'name': ['batterie', 'batt', 'Voltage'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_bat_', 'val_tpl': "{{ (value_json['batt']['Voltage'] | float)}}", 'name': 'Batterie Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_CUR: {'name': ['batterie', 'batt', 'Current'], 'level': logging.INFO, 'unit': 'A', 'ha': {'dev': 'batterie', 'dev_cla': 'current', 'stat_cla': 'measurement', 'id': 'cur_bat_', 'val_tpl': "{{ (value_json['batt']['Current'] | float)}}", 'name': 'Batterie Current', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_PWR: {'name': ['batterie', 'batt', 'Power'], 'level': logging.INFO, 'unit': 'W', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'power_', 'val_tpl': "{{ (value_json['batt']['Power'] | int)}}", 'name': 'Batterie Power'}}, # noqa: E501
|
||||
Register.BATT_SOC: {'name': ['batterie', 'batt', 'SOC'], 'level': logging.INFO, 'unit': '%', 'ha': {'dev': 'batterie', 'dev_cla': None, 'stat_cla': 'measurement', 'id': 'soc_', 'val_tpl': "{{ (value_json['batt']['SOC'] | float)}}", 'name': 'State of Charge (SOC)', 'icon': 'mdi:battery-90'}}, # noqa: E501
|
||||
Register.BATT_TOTAL_CHARG: {'name': ['batterie', 'batt', 'Total_Charging'], 'level': logging.INFO, 'unit': 'kWh', 'ha': {'dev': 'batterie', 'dev_cla': 'energy', 'stat_cla': 'total', 'id': 'total_charg_', 'val_tpl': "{{ (value_json['batt']['Total_Charging'] | float)}}", 'name': TOTAL_CHARG, 'icon': 'mdi:battery-charging', 'must_incr': True}}, # noqa: E501
|
||||
Register.BATT_STATUS: {'name': ['batterie', 'batt', 'Batt_State'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'status_batt_', 'name': 'Batterie State', 'val_tpl': __batt_status_type_val_tpl, 'icon': POWER}}, # noqa: E501
|
||||
|
||||
Register.BATT_TEMP_1: {'name': ['batterie', 'cell', 'Temp_1'], 'level': logging.INFO, 'unit': '°C', 'ha': {'dev': 'batterie', 'dev_cla': 'temperature', 'stat_cla': 'measurement', 'id': 'temp_1_', 'val_tpl': "{{ (value_json['cell']['Temp_1'] | int)}}", 'name': 'Cell Temp-1', 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_TEMP_2: {'name': ['batterie', 'cell', 'Temp_2'], 'level': logging.INFO, 'unit': '°C', 'ha': {'dev': 'batterie', 'dev_cla': 'temperature', 'stat_cla': 'measurement', 'id': 'temp_2_', 'val_tpl': "{{ (value_json['cell']['Temp_2'] | int)}}", 'name': 'Cell Temp-2', 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_TEMP_3: {'name': ['batterie', 'cell', 'Temp_3'], 'level': logging.INFO, 'unit': '°C', 'ha': {'dev': 'batterie', 'dev_cla': 'temperature', 'stat_cla': 'measurement', 'id': 'temp_3_', 'val_tpl': "{{ (value_json['cell']['Temp_3'] | int)}}", 'name': 'Cell Temp-3', 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_TEMP_4: {'name': ['batterie', 'Controller_Temp'], 'level': logging.INFO, 'unit': '°C', 'ha': {'dev': 'batterie', 'dev_cla': 'temperature', 'stat_cla': 'measurement', 'id': 'temp_4_', 'fmt': FMT_INT, 'name': 'Temperature'}}, # noqa: E501
|
||||
Register.BATT_ALARM: {'name': ['batterie', 'Batterie_Alarm'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'batt_alarm_', 'name': 'Batterie Alarm', 'val_tpl': __batt_alarm_val_tpl, 'icon': ALARM_LIGHT}}, # noqa: E501
|
||||
Register.BATT_HW_VERS: {'name': ['batterie', 'Hardware_Version'], 'level': logging.INFO, 'unit': ''}, # noqa: E501
|
||||
Register.BATT_SW_VERS: {'name': ['batterie', 'Software_Version'], 'level': logging.INFO, 'unit': ''}, # noqa: E501
|
||||
Register.BATT_OUT_STATUS: {'name': ['batterie', 'out', 'Out_Status'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'out_status_', 'name': 'Output Status', 'val_tpl': __out_status_type_val_tpl, 'icon': POWER}}, # noqa: E501
|
||||
Register.BATT_TEMP_4: {'name': ['batterie', 'Controller_Temp'], 'level': logging.INFO, 'unit': '°C', 'ha': {'dev': 'batterie', 'dev_cla': 'temperature', 'stat_cla': 'measurement', 'id': 'temp_4_', 'fmt': FMT_INT, 'name': 'Ctrl Temperature'}}, # noqa: E501
|
||||
Register.BATT_74: {'name': ['batterie', 'Reg_74'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_74_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_76: {'name': ['batterie', 'Reg_76'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_76_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_78: {'name': ['batterie', 'Reg_78'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_78_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.BATT_PV_PWR: {'name': ['batterie', 'PV_Power'], 'level': logging.INFO, 'unit': 'W', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'pv_power_', 'fmt': FMT_INT, 'name': 'PV Power'}}, # noqa: E501
|
||||
Register.BATT_PWR: {'name': ['batterie', 'Power'], 'level': logging.INFO, 'unit': 'W', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'power_', 'fmt': FMT_INT, 'name': 'Batterie Power'}}, # noqa: E501
|
||||
Register.BATT_OUT_PWR: {'name': ['batterie', 'out', 'Power'], 'level': logging.INFO, 'unit': 'W', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'out_power_', 'val_tpl': "{{ (value_json['out']['Power'] | int)}}", 'name': 'Output Power'}}, # noqa: E501
|
||||
|
||||
Register.TEST_VAL_0: {'name': ['input', 'Val_0'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'inverter', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'val_0_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
Register.TEST_VAL_1: {'name': ['input', 'Val_1'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'inverter', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'val_1_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501
|
||||
@@ -840,10 +764,7 @@ class Infos:
|
||||
def inc_counter(cls, counter: str) -> None:
|
||||
'''inc proxy statistic counter'''
|
||||
db_dict = cls.stat['proxy']
|
||||
try:
|
||||
db_dict[counter] += 1
|
||||
except Exception:
|
||||
db_dict[counter] = 1
|
||||
db_dict[counter] += 1
|
||||
cls.new_stat_data['proxy'] = True
|
||||
|
||||
@classmethod
|
||||
@@ -853,15 +774,6 @@ class Infos:
|
||||
db_dict[counter] -= 1
|
||||
cls.new_stat_data['proxy'] = True
|
||||
|
||||
@classmethod
|
||||
def get_counter(cls, counter: str) -> int:
|
||||
'''get proxy statistic counter'''
|
||||
try:
|
||||
db_dict = cls.stat['proxy']
|
||||
return db_dict[counter]
|
||||
except Exception:
|
||||
return 0
|
||||
|
||||
def ha_proxy_confs(self, ha_prfx: str, node_id: str, snr: str) \
|
||||
-> Generator[tuple[str, str, str, str], None, None]:
|
||||
'''Generator function yields json register struct for home-assistant
|
||||
|
||||
@@ -4,7 +4,6 @@ import logging
|
||||
import traceback
|
||||
import json
|
||||
import gc
|
||||
import socket
|
||||
from aiomqtt import MqttCodeError
|
||||
from asyncio import StreamReader, StreamWriter
|
||||
from ipaddress import ip_address
|
||||
@@ -29,24 +28,20 @@ class InverterBase(InverterIfc, Proxy):
|
||||
Proxy.__init__(self)
|
||||
self._registry.append(weakref.ref(self))
|
||||
self.addr = writer.get_extra_info('peername')
|
||||
self.client_mode = client_mode
|
||||
self.config_id = config_id
|
||||
if remote_prot_class:
|
||||
self.prot_class = remote_prot_class
|
||||
self.use_emulation = True
|
||||
else:
|
||||
self.prot_class = prot_class
|
||||
self.use_emulation = False
|
||||
self.__ha_restarts = -1
|
||||
self.remote = StreamPtr(None)
|
||||
self.background_tasks = set()
|
||||
ifc = AsyncStreamServer(reader, writer,
|
||||
self.async_publ_mqtt,
|
||||
self.create_remote,
|
||||
self.remote)
|
||||
|
||||
self.local = StreamPtr(
|
||||
prot_class(self, self.addr, ifc, True, client_mode), ifc
|
||||
prot_class(self.addr, ifc, True, client_mode), ifc
|
||||
)
|
||||
|
||||
def __enter__(self):
|
||||
@@ -74,7 +69,6 @@ class InverterBase(InverterIfc, Proxy):
|
||||
if self.remote.ifc:
|
||||
self.remote.ifc.close()
|
||||
self.remote.ifc = None
|
||||
self.background_tasks.clear()
|
||||
|
||||
async def disc(self, shutdown_started=False) -> None:
|
||||
if self.remote.stream:
|
||||
@@ -123,30 +117,24 @@ class InverterBase(InverterIfc, Proxy):
|
||||
Config.act_config[self.config_id]['enabled'] = False
|
||||
|
||||
ifc = AsyncStreamClient(
|
||||
reader, writer, self.local,
|
||||
self.__del_remote, self.use_emulation)
|
||||
reader, writer, self.local, self.__del_remote)
|
||||
|
||||
self.remote.ifc = ifc
|
||||
if hasattr(stream, 'id_str'):
|
||||
self.remote.stream = self.prot_class(
|
||||
self, addr, ifc, server_side=False,
|
||||
addr, ifc, server_side=False,
|
||||
client_mode=False, id_str=stream.id_str)
|
||||
else:
|
||||
self.remote.stream = self.prot_class(
|
||||
self, addr, ifc, server_side=False,
|
||||
addr, ifc, server_side=False,
|
||||
client_mode=False)
|
||||
|
||||
logging.info(f'[{self.remote.stream.node_id}:'
|
||||
f'{self.remote.stream.conn_no}] '
|
||||
f'Connected to {addr}')
|
||||
task = asyncio.create_task(
|
||||
self.remote.ifc.client_loop(addr))
|
||||
self.background_tasks.add(task)
|
||||
task.add_done_callback(self.background_tasks.discard)
|
||||
asyncio.create_task(self.remote.ifc.client_loop(addr))
|
||||
|
||||
except (ConnectionRefusedError,
|
||||
TimeoutError,
|
||||
socket.gaierror) as error:
|
||||
except (ConnectionRefusedError, TimeoutError) as error:
|
||||
logging.info(f'{error}')
|
||||
except Exception:
|
||||
Infos.inc_counter('SW_Exception')
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
[loggers]
|
||||
keys=root,tracer,mesg,conn,data,mqtt,asyncio,hypercorn_access,hypercorn_error
|
||||
keys=root,tracer,mesg,conn,data,mqtt,asyncio
|
||||
|
||||
[handlers]
|
||||
keys=console_handler,file_handler_name1,file_handler_name2,file_handler_name3,dashboard
|
||||
keys=console_handler,file_handler_name1,file_handler_name2
|
||||
|
||||
[formatters]
|
||||
keys=console_formatter,file_formatter
|
||||
|
||||
[logger_root]
|
||||
level=DEBUG
|
||||
handlers=console_handler,file_handler_name1,dashboard
|
||||
handlers=console_handler,file_handler_name1
|
||||
|
||||
|
||||
[logger_conn]
|
||||
level=DEBUG
|
||||
@@ -19,13 +20,13 @@ qualname=conn
|
||||
|
||||
[logger_mqtt]
|
||||
level=INFO
|
||||
handlers=console_handler,file_handler_name1,dashboard
|
||||
handlers=console_handler,file_handler_name1
|
||||
propagate=0
|
||||
qualname=mqtt
|
||||
|
||||
[logger_asyncio]
|
||||
level=INFO
|
||||
handlers=console_handler,file_handler_name1,dashboard
|
||||
handlers=console_handler,file_handler_name1
|
||||
propagate=0
|
||||
qualname=asyncio
|
||||
|
||||
@@ -48,18 +49,6 @@ handlers=file_handler_name2
|
||||
propagate=0
|
||||
qualname=tracer
|
||||
|
||||
[logger_hypercorn_access]
|
||||
level=INFO
|
||||
handlers=file_handler_name3
|
||||
propagate=0
|
||||
qualname=hypercorn.access
|
||||
|
||||
[logger_hypercorn_error]
|
||||
level=INFO
|
||||
handlers=file_handler_name1,dashboard
|
||||
propagate=0
|
||||
qualname=hypercorn.error
|
||||
|
||||
[handler_console_handler]
|
||||
class=StreamHandler
|
||||
level=DEBUG
|
||||
@@ -77,16 +66,6 @@ level=NOTSET
|
||||
formatter=file_formatter
|
||||
args=(handlers.log_path + 'trace.log', when:='midnight', backupCount:=handlers.log_backups)
|
||||
|
||||
[handler_file_handler_name3]
|
||||
class=handlers.TimedRotatingFileHandler
|
||||
level=NOTSET
|
||||
formatter=file_formatter
|
||||
args=(handlers.log_path + 'access.log', when:='midnight', backupCount:=handlers.log_backups)
|
||||
|
||||
[handler_dashboard]
|
||||
level=WARNING
|
||||
class=web.log_handler.LogHandler
|
||||
|
||||
[formatter_console_formatter]
|
||||
format=%(asctime)s %(levelname)5s | %(name)4s | %(message)s
|
||||
datefmt=%Y-%m-%d %H:%M:%S
|
||||
|
||||
@@ -108,7 +108,6 @@ class Message(ProtocolIfc):
|
||||
self.header_len = 0
|
||||
self.data_len = 0
|
||||
self.unique_id = 0
|
||||
self.inv_serial = ''
|
||||
self.sug_area = ''
|
||||
self.new_data = {}
|
||||
self.state = State.init
|
||||
@@ -141,9 +140,8 @@ class Message(ProtocolIfc):
|
||||
# to our _recv_buffer
|
||||
return # pragma: no cover
|
||||
|
||||
def _set_config_parms(self, inv: dict, inv_serial: str):
|
||||
def _set_config_parms(self, inv: dict):
|
||||
'''init connection with params from the configuration'''
|
||||
self.inv_serial = inv_serial
|
||||
self.node_id = inv['node_id']
|
||||
self.sug_area = inv['suggested_area']
|
||||
self.modbus_polling = inv['modbus_polling']
|
||||
@@ -193,7 +191,7 @@ class Message(ProtocolIfc):
|
||||
return
|
||||
self.mb.build_msg(dev_id, func, addr, val, log_lvl)
|
||||
|
||||
def send_modbus_cmd(self, func, addr, val, log_lvl) -> None:
|
||||
async def send_modbus_cmd(self, func, addr, val, log_lvl) -> None:
|
||||
self._send_modbus_cmd(Modbus.INV_ADDR, func, addr, val, log_lvl)
|
||||
|
||||
def _send_modbus_scan(self):
|
||||
|
||||
@@ -42,38 +42,39 @@ class Modbus():
|
||||
0x0009: {'reg': Register.BATT_PV1_CUR, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, PV1 current
|
||||
0x000a: {'reg': Register.BATT_PV2_VOLT, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, PV2 voltage
|
||||
0x000b: {'reg': Register.BATT_PV2_CUR, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, PV2 current
|
||||
0x000c: {'reg': Register.BATT_TOTAL_CHARG, 'fmt': '!L', 'ratio': 0.01}, # noqa: E501
|
||||
0x000e: {'reg': Register.BATT_PV1_STATUS, 'fmt': '!H'}, # noqa: E501
|
||||
0x000f: {'reg': Register.BATT_PV2_STATUS, 'fmt': '!H'}, # noqa: E501
|
||||
0x000c: {'reg': Register.BATT_38, 'fmt': '!h'}, # noqa: E501
|
||||
0x000d: {'reg': Register.BATT_TOTAL_GEN, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501
|
||||
0x000e: {'reg': Register.BATT_STATUS_1, 'fmt': '!h'}, # noqa: E501
|
||||
0x000f: {'reg': Register.BATT_STATUS_2, 'fmt': '!h'}, # noqa: E501
|
||||
0x0010: {'reg': Register.BATT_VOLT, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501
|
||||
0x0011: {'reg': Register.BATT_CUR, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501
|
||||
0x0012: {'reg': Register.BATT_SOC, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, state of charge (SOC) in percent
|
||||
0x0013: {'reg': Register.BATT_CELL1_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x0014: {'reg': Register.BATT_CELL2_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x0015: {'reg': Register.BATT_CELL3_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x0016: {'reg': Register.BATT_CELL4_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x0017: {'reg': Register.BATT_CELL5_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x0018: {'reg': Register.BATT_CELL6_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x0019: {'reg': Register.BATT_CELL7_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x001a: {'reg': Register.BATT_CELL8_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x001b: {'reg': Register.BATT_CELL9_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x001c: {'reg': Register.BATT_CELL10_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x001d: {'reg': Register.BATT_CELL11_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x001e: {'reg': Register.BATT_CELL12_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x001f: {'reg': Register.BATT_CELL13_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x0020: {'reg': Register.BATT_CELL14_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x0021: {'reg': Register.BATT_CELL15_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x0022: {'reg': Register.BATT_CELL16_VOLT, 'fmt': '!H', 'ratio': 0.001}, # noqa: E501
|
||||
0x0013: {'reg': Register.BATT_CELL1_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x0014: {'reg': Register.BATT_CELL2_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x0015: {'reg': Register.BATT_CELL3_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x0016: {'reg': Register.BATT_CELL4_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x0017: {'reg': Register.BATT_CELL5_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x0018: {'reg': Register.BATT_CELL6_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x0019: {'reg': Register.BATT_CELL7_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x001a: {'reg': Register.BATT_CELL8_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x001b: {'reg': Register.BATT_CELL9_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x001c: {'reg': Register.BATT_CELL10_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x001d: {'reg': Register.BATT_CELL11_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x001e: {'reg': Register.BATT_CELL12_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x001f: {'reg': Register.BATT_CELL13_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x0020: {'reg': Register.BATT_CELL14_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x0021: {'reg': Register.BATT_CELL15_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x0022: {'reg': Register.BATT_CELL16_VOLT, 'fmt': '!h', 'ratio': 0.001}, # noqa: E501
|
||||
0x0023: {'reg': Register.BATT_TEMP_1, 'fmt': '!h'}, # noqa: E501
|
||||
0x0024: {'reg': Register.BATT_TEMP_2, 'fmt': '!h'}, # noqa: E501
|
||||
0x0025: {'reg': Register.BATT_TEMP_3, 'fmt': '!h'}, # noqa: E501
|
||||
0x0026: {'reg': Register.BATT_OUT_VOLT, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501
|
||||
0x0027: {'reg': Register.BATT_OUT_CUR, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501
|
||||
0x0028: {'reg': Register.BATT_OUT_STATUS, 'fmt': '!H'}, # noqa: E501
|
||||
0x0026: {'reg': Register.BATT_OUT_VOLT, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501
|
||||
0x0027: {'reg': Register.BATT_OUT_CUR, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501
|
||||
0x0028: {'reg': Register.BATT_OUT_STATUS, 'fmt': '!h'}, # noqa: E501
|
||||
0x0029: {'reg': Register.BATT_TEMP_4, 'fmt': '!h'}, # noqa: E501
|
||||
0x002a: {'reg': Register.BATT_ALARM, 'fmt': '!h'}, # noqa: E501
|
||||
0x002b: {'reg': Register.BATT_HW_VERS, 'fmt': '!h'}, # noqa: E501
|
||||
0x002c: {'reg': Register.BATT_SW_VERS, 'fmt': '!h'}, # noqa: E501
|
||||
0x002a: {'reg': Register.BATT_74, 'fmt': '!h'}, # noqa: E501
|
||||
0x002b: {'reg': Register.BATT_76, 'fmt': '!h'}, # noqa: E501
|
||||
0x002c: {'reg': Register.BATT_78, 'fmt': '!h'}, # noqa: E501
|
||||
|
||||
0x2000: {'reg': Register.BOOT_STATUS, 'fmt': '!H'}, # noqa: E501
|
||||
0x2001: {'reg': Register.DSP_STATUS, 'fmt': '!H'}, # noqa: E501
|
||||
|
||||
@@ -28,12 +28,10 @@ class ModbusConn():
|
||||
logging.info(f'[{stream.node_id}:{stream.conn_no}] '
|
||||
f'Connected to {self.addr}')
|
||||
Infos.inc_counter('Inverter_Cnt')
|
||||
Infos.inc_counter('ClientMode_Cnt')
|
||||
await self.inverter.local.ifc.publish_outstanding_mqtt()
|
||||
return self.inverter
|
||||
|
||||
async def __aexit__(self, exc_type, exc, tb):
|
||||
Infos.dec_counter('ClientMode_Cnt')
|
||||
Infos.dec_counter('Inverter_Cnt')
|
||||
await self.inverter.local.ifc.publish_outstanding_mqtt()
|
||||
self.inverter.__exit__(exc_type, exc, tb)
|
||||
@@ -43,7 +41,6 @@ class ModbusTcp():
|
||||
|
||||
def __init__(self, loop, tim_restart=10) -> None:
|
||||
self.tim_restart = tim_restart
|
||||
self.background_tasks = set()
|
||||
|
||||
inverters = Config.get('inverters')
|
||||
batteries = Config.get('batteries')
|
||||
@@ -55,13 +52,10 @@ class ModbusTcp():
|
||||
and 'client_mode' in inv):
|
||||
client = inv['client_mode']
|
||||
logger.info(f"'client_mode' for Monitoring-SN: {inv['monitor_sn']} host: {client['host']}:{client['port']}, forward: {client['forward']}") # noqa: E501
|
||||
task = loop.create_task(
|
||||
self.modbus_loop(client['host'],
|
||||
client['port'],
|
||||
inv['monitor_sn'],
|
||||
client['forward']))
|
||||
self.background_tasks.add(task)
|
||||
task.add_done_callback(self.background_tasks.discard)
|
||||
loop.create_task(self.modbus_loop(client['host'],
|
||||
client['port'],
|
||||
inv['monitor_sn'],
|
||||
client['forward']))
|
||||
|
||||
async def modbus_loop(self, host, port,
|
||||
snr: int, forward: bool) -> None:
|
||||
@@ -70,7 +64,7 @@ class ModbusTcp():
|
||||
try:
|
||||
async with ModbusConn(host, port) as inverter:
|
||||
stream = inverter.local.stream
|
||||
stream.send_start_cmd(snr, host, forward)
|
||||
await stream.send_start_cmd(snr, host, forward)
|
||||
await stream.ifc.loop()
|
||||
logger.info(f'[{stream.node_id}:{stream.conn_no}] '
|
||||
f'Connection closed - Shutdown: '
|
||||
|
||||
150
app/src/mqtt.py
Executable file → Normal file
@@ -2,25 +2,18 @@ import asyncio
|
||||
import logging
|
||||
import aiomqtt
|
||||
import traceback
|
||||
import struct
|
||||
import inspect
|
||||
|
||||
from modbus import Modbus
|
||||
from messages import Message
|
||||
from cnf.config import Config
|
||||
from singleton import Singleton
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
logger_mqtt = logging.getLogger('mqtt')
|
||||
|
||||
|
||||
class Mqtt(metaclass=Singleton):
|
||||
__client: aiomqtt.Client = None
|
||||
__client = None
|
||||
__cb_mqtt_is_up = None
|
||||
ctime = None
|
||||
published: int = 0
|
||||
received: int = 0
|
||||
|
||||
def __init__(self, cb_mqtt_is_up):
|
||||
logger_mqtt.debug('MQTT: __init__')
|
||||
@@ -29,27 +22,14 @@ class Mqtt(metaclass=Singleton):
|
||||
loop = asyncio.get_event_loop()
|
||||
self.task = loop.create_task(self.__loop())
|
||||
self.ha_restarts = 0
|
||||
self.topic_defs = [
|
||||
{'prefix': 'auto_conf_prefix', 'topic': '/status',
|
||||
'fnc': self._ha_status, 'args': []},
|
||||
{'prefix': 'entity_prefix', 'topic': '/+/rated_load',
|
||||
'fnc': self._modbus_cmd,
|
||||
'args': [Modbus.WRITE_SINGLE_REG, 1, 0x2008]},
|
||||
{'prefix': 'entity_prefix', 'topic': '/+/out_coeff',
|
||||
'fnc': self._out_coeff, 'args': []},
|
||||
{'prefix': 'entity_prefix', 'topic': '/+/dcu_power',
|
||||
'fnc': self._dcu_cmd, 'args': []},
|
||||
{'prefix': 'entity_prefix', 'topic': '/+/modbus_read_regs',
|
||||
'fnc': self._modbus_cmd, 'args': [Modbus.READ_REGS, 2]},
|
||||
{'prefix': 'entity_prefix', 'topic': '/+/modbus_read_inputs',
|
||||
'fnc': self._modbus_cmd, 'args': [Modbus.READ_INPUTS, 2]},
|
||||
{'prefix': 'entity_prefix', 'topic': '/+/at_cmd',
|
||||
'fnc': self._at_cmd, 'args': []},
|
||||
]
|
||||
|
||||
ha = Config.get('ha')
|
||||
for entry in self.topic_defs:
|
||||
entry['full_topic'] = f"{ha[entry['prefix']]}{entry['topic']}"
|
||||
self.ha_status_topic = f"{ha['auto_conf_prefix']}/status"
|
||||
self.mb_rated_topic = f"{ha['entity_prefix']}/+/rated_load"
|
||||
self.mb_out_coeff_topic = f"{ha['entity_prefix']}/+/out_coeff"
|
||||
self.mb_reads_topic = f"{ha['entity_prefix']}/+/modbus_read_regs"
|
||||
self.mb_inputs_topic = f"{ha['entity_prefix']}/+/modbus_read_inputs"
|
||||
self.mb_at_cmd_topic = f"{ha['entity_prefix']}/+/at_cmd"
|
||||
|
||||
@property
|
||||
def ha_restarts(self):
|
||||
@@ -72,7 +52,6 @@ class Mqtt(metaclass=Singleton):
|
||||
| int | float | None = None) -> None:
|
||||
if self.__client:
|
||||
await self.__client.publish(topic, payload)
|
||||
self.published += 1
|
||||
|
||||
async def __loop(self) -> None:
|
||||
mqtt = Config.get('mqtt')
|
||||
@@ -90,14 +69,21 @@ class Mqtt(metaclass=Singleton):
|
||||
try:
|
||||
async with self.__client:
|
||||
logger_mqtt.info('MQTT broker connection established')
|
||||
await self._init_new_conn()
|
||||
|
||||
if self.__cb_mqtt_is_up:
|
||||
await self.__cb_mqtt_is_up()
|
||||
|
||||
await self.__client.subscribe(self.ha_status_topic)
|
||||
await self.__client.subscribe(self.mb_rated_topic)
|
||||
await self.__client.subscribe(self.mb_out_coeff_topic)
|
||||
await self.__client.subscribe(self.mb_reads_topic)
|
||||
await self.__client.subscribe(self.mb_inputs_topic)
|
||||
await self.__client.subscribe(self.mb_at_cmd_topic)
|
||||
|
||||
async for message in self.__client.messages:
|
||||
await self.dispatch_msg(message)
|
||||
|
||||
except aiomqtt.MqttError:
|
||||
self.ctime = None
|
||||
|
||||
if Config.is_default('mqtt'):
|
||||
logger_mqtt.info(
|
||||
"MQTT is unconfigured; Check your config.toml!")
|
||||
@@ -112,59 +98,52 @@ class Mqtt(metaclass=Singleton):
|
||||
except asyncio.CancelledError:
|
||||
logger_mqtt.debug("MQTT task cancelled")
|
||||
self.__client = None
|
||||
raise
|
||||
return
|
||||
except Exception:
|
||||
# self.inc_counter('SW_Exception') # fixme
|
||||
self.ctime = None
|
||||
logger_mqtt.error(
|
||||
f"Exception:\n"
|
||||
f"{traceback.format_exc()}")
|
||||
|
||||
async def _init_new_conn(self):
|
||||
self.ctime = datetime.now()
|
||||
self.published = 0
|
||||
self.received = 0
|
||||
if self.__cb_mqtt_is_up:
|
||||
await self.__cb_mqtt_is_up()
|
||||
for entry in self.topic_defs:
|
||||
await self.__client.subscribe(entry['full_topic'])
|
||||
|
||||
async def dispatch_msg(self, message):
|
||||
self.received += 1
|
||||
|
||||
for entry in self.topic_defs:
|
||||
if message.topic.matches(entry['full_topic']) \
|
||||
and 'fnc' in entry:
|
||||
fnc = entry['fnc']
|
||||
|
||||
if inspect.iscoroutinefunction(fnc):
|
||||
await entry['fnc'](message, *entry['args'])
|
||||
elif callable(fnc):
|
||||
entry['fnc'](message, *entry['args'])
|
||||
|
||||
async def _ha_status(self, message):
|
||||
status = message.payload.decode("UTF-8")
|
||||
logger_mqtt.info('Home-Assistant Status:'
|
||||
f' {status}')
|
||||
if status == 'online':
|
||||
self.ha_restarts += 1
|
||||
if self.__cb_mqtt_is_up:
|
||||
if message.topic.matches(self.ha_status_topic):
|
||||
status = message.payload.decode("UTF-8")
|
||||
logger_mqtt.info('Home-Assistant Status:'
|
||||
f' {status}')
|
||||
if status == 'online':
|
||||
self.ha_restarts += 1
|
||||
await self.__cb_mqtt_is_up()
|
||||
|
||||
def _out_coeff(self, message):
|
||||
payload = message.payload.decode("UTF-8")
|
||||
try:
|
||||
val = round(float(payload) * 1024/100)
|
||||
if val < 0 or val > 1024:
|
||||
logger_mqtt.error('out_coeff: value must be in'
|
||||
'the range 0..100,'
|
||||
f' got: {payload}')
|
||||
else:
|
||||
self._modbus_cmd(message,
|
||||
Modbus.WRITE_SINGLE_REG,
|
||||
0, 0x202c, val)
|
||||
except Exception:
|
||||
pass
|
||||
if message.topic.matches(self.mb_rated_topic):
|
||||
await self.modbus_cmd(message,
|
||||
Modbus.WRITE_SINGLE_REG,
|
||||
1, 0x2008)
|
||||
|
||||
if message.topic.matches(self.mb_out_coeff_topic):
|
||||
payload = message.payload.decode("UTF-8")
|
||||
try:
|
||||
val = round(float(payload) * 1024/100)
|
||||
if val < 0 or val > 1024:
|
||||
logger_mqtt.error('out_coeff: value must be in'
|
||||
'the range 0..100,'
|
||||
f' got: {payload}')
|
||||
else:
|
||||
await self.modbus_cmd(message,
|
||||
Modbus.WRITE_SINGLE_REG,
|
||||
0, 0x202c, val)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if message.topic.matches(self.mb_reads_topic):
|
||||
await self.modbus_cmd(message,
|
||||
Modbus.READ_REGS, 2)
|
||||
|
||||
if message.topic.matches(self.mb_inputs_topic):
|
||||
await self.modbus_cmd(message,
|
||||
Modbus.READ_INPUTS, 2)
|
||||
|
||||
if message.topic.matches(self.mb_at_cmd_topic):
|
||||
await self.at_cmd(message)
|
||||
|
||||
def each_inverter(self, message, func_name: str):
|
||||
topic = str(message.topic)
|
||||
@@ -182,7 +161,7 @@ class Mqtt(metaclass=Singleton):
|
||||
else:
|
||||
logger_mqtt.warning(f'Node_id: {node_id} not found')
|
||||
|
||||
def _modbus_cmd(self, message, func, params=0, addr=0, val=0):
|
||||
async def modbus_cmd(self, message, func, params=0, addr=0, val=0):
|
||||
payload = message.payload.decode("UTF-8")
|
||||
for fnc in self.each_inverter(message, "send_modbus_cmd"):
|
||||
res = payload.split(',')
|
||||
@@ -195,24 +174,9 @@ class Mqtt(metaclass=Singleton):
|
||||
elif params == 2:
|
||||
addr = int(res[0], base=16)
|
||||
val = int(res[1]) # lenght
|
||||
fnc(func, addr, val, logging.INFO)
|
||||
await fnc(func, addr, val, logging.INFO)
|
||||
|
||||
async def _at_cmd(self, message):
|
||||
async def at_cmd(self, message):
|
||||
payload = message.payload.decode("UTF-8")
|
||||
for fnc in self.each_inverter(message, "send_at_cmd"):
|
||||
await fnc(payload)
|
||||
|
||||
def _dcu_cmd(self, message):
|
||||
payload = message.payload.decode("UTF-8")
|
||||
try:
|
||||
val = round(float(payload) * 10)
|
||||
if val < 1000 or val > 8000:
|
||||
logger_mqtt.error('dcu_power: value must be in'
|
||||
'the range 100..800,'
|
||||
f' got: {payload}')
|
||||
else:
|
||||
pdu = struct.pack('>BBBBBBH', 1, 1, 6, 1, 0, 1, val)
|
||||
for fnc in self.each_inverter(message, "send_dcu_cmd"):
|
||||
fnc(pdu)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@@ -96,8 +96,8 @@ class Proxy():
|
||||
Infos.new_stat_data[key] = False
|
||||
|
||||
@classmethod
|
||||
async def class_close(cls, loop) -> None: # pragma: no cover
|
||||
def class_close(cls, loop) -> None: # pragma: no cover
|
||||
logging.debug('Proxy.class_close')
|
||||
logging.info('Close MQTT Task')
|
||||
await cls.mqtt.close()
|
||||
loop.run_until_complete(cls.mqtt.close())
|
||||
cls.mqtt = None
|
||||
|
||||
@@ -12,7 +12,7 @@ class Schedule:
|
||||
count = 0
|
||||
|
||||
@classmethod
|
||||
def start(cls) -> None: # pragma: no cover
|
||||
def start(cls) -> None:
|
||||
'''Start the scheduler and schedule the tasks (cron jobs)'''
|
||||
logging.debug("Scheduler init")
|
||||
cls.mqtt = Mqtt(None)
|
||||
@@ -20,7 +20,7 @@ class Schedule:
|
||||
crontab('0 0 * * *', func=cls.atmidnight, start=True)
|
||||
|
||||
@classmethod
|
||||
async def atmidnight(cls) -> None: # pragma: no cover
|
||||
async def atmidnight(cls) -> None:
|
||||
'''Clear daily counters at midnight'''
|
||||
logging.info("Clear daily counters at midnight")
|
||||
|
||||
|
||||
@@ -1,296 +1,93 @@
|
||||
import logging
|
||||
import logging.handlers
|
||||
from logging import config # noqa F401
|
||||
import asyncio
|
||||
from asyncio import StreamReader, StreamWriter
|
||||
import logging.handlers
|
||||
import signal
|
||||
import os
|
||||
import argparse
|
||||
from quart import Quart, Response
|
||||
|
||||
from cnf.config import Config
|
||||
from cnf.config_read_env import ConfigReadEnv
|
||||
from cnf.config_read_toml import ConfigReadToml
|
||||
from cnf.config_read_json import ConfigReadJson
|
||||
from web import Web
|
||||
from web.wrapper import url_for
|
||||
from asyncio import StreamReader, StreamWriter
|
||||
from aiohttp import web
|
||||
from logging import config # noqa F401
|
||||
from proxy import Proxy
|
||||
from inverter_ifc import InverterIfc
|
||||
from gen3.inverter_g3 import InverterG3
|
||||
from gen3plus.inverter_g3p import InverterG3P
|
||||
from scheduler import Schedule
|
||||
|
||||
from cnf.config import Config
|
||||
from cnf.config_read_env import ConfigReadEnv
|
||||
from cnf.config_read_toml import ConfigReadToml
|
||||
from cnf.config_read_json import ConfigReadJson
|
||||
from modbus_tcp import ModbusTcp
|
||||
|
||||
|
||||
class Server():
|
||||
serv_name = ''
|
||||
version = ''
|
||||
src_dir = ''
|
||||
|
||||
####
|
||||
# The following default values are used for the unit tests only, since
|
||||
# `Server.parse_args()' will not be called during test setup.
|
||||
# Ofcorse, we can call `Server.parse_args()' in a test case explicitly
|
||||
# to overwrite this values
|
||||
config_path = './config/'
|
||||
json_config = ''
|
||||
toml_config = ''
|
||||
trans_path = '../translations/'
|
||||
rel_urls = False
|
||||
log_path = './log/'
|
||||
log_backups = 0
|
||||
log_level = None
|
||||
|
||||
def __init__(self, app, parse_args: bool):
|
||||
''' Applikation Setup
|
||||
|
||||
1. Read cli arguments
|
||||
2. Init the logging system by the ini file
|
||||
3. Log the config parms
|
||||
4. Set the log-levels
|
||||
5. Read the build the config for the app
|
||||
'''
|
||||
self.serv_name = os.getenv('SERVICE_NAME', 'proxy')
|
||||
self.version = os.getenv('VERSION', 'unknown')
|
||||
self.src_dir = os.path.dirname(__file__) + '/'
|
||||
if parse_args: # pragma: no cover
|
||||
self.parse_args(None)
|
||||
self.init_logging_system()
|
||||
self.build_config()
|
||||
|
||||
@app.context_processor
|
||||
def utility_processor():
|
||||
var = {'version': self.version,
|
||||
'slug': os.getenv("SLUG"),
|
||||
'hostname': os.getenv("HOSTNAME"),
|
||||
}
|
||||
if var['slug']:
|
||||
var['hassio'] = True
|
||||
slug_len = len(var['slug'])
|
||||
var['addonname'] = var['slug'] + '_' + \
|
||||
var['hostname'][slug_len+1:]
|
||||
return var
|
||||
|
||||
def parse_args(self, arg_list: list[str] | None):
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-c', '--config_path', type=str,
|
||||
default='./config/',
|
||||
help='set path for the configuration files')
|
||||
parser.add_argument('-j', '--json_config', type=str,
|
||||
help='read user config from json-file')
|
||||
parser.add_argument('-t', '--toml_config', type=str,
|
||||
help='read user config from toml-file')
|
||||
parser.add_argument('-l', '--log_path', type=str,
|
||||
default='./log/',
|
||||
help='set path for the logging files')
|
||||
parser.add_argument('-b', '--log_backups', type=int,
|
||||
default=0,
|
||||
help='set max number of daily log-files')
|
||||
parser.add_argument('-tr', '--trans_path', type=str,
|
||||
default='../translations/',
|
||||
help='set path for the translations files')
|
||||
parser.add_argument('-r', '--rel_urls', action="store_true",
|
||||
help='use relative dashboard urls')
|
||||
args = parser.parse_args(arg_list)
|
||||
|
||||
self.config_path = args.config_path
|
||||
self.json_config = args.json_config
|
||||
self.toml_config = args.toml_config
|
||||
self.trans_path = args.trans_path
|
||||
self.rel_urls = args.rel_urls
|
||||
self.log_path = args.log_path
|
||||
self.log_backups = args.log_backups
|
||||
|
||||
def init_logging_system(self):
|
||||
setattr(logging.handlers, "log_path", self.log_path)
|
||||
setattr(logging.handlers, "log_backups", self.log_backups)
|
||||
os.makedirs(self.log_path, exist_ok=True)
|
||||
|
||||
logging.config.fileConfig(self.src_dir + 'logging.ini')
|
||||
|
||||
logging.info(
|
||||
f'Server "{self.serv_name} - {self.version}" will be started')
|
||||
logging.info(f'current dir: {os.getcwd()}')
|
||||
logging.info(f"config_path: {self.config_path}")
|
||||
logging.info(f"json_config: {self.json_config}")
|
||||
logging.info(f"toml_config: {self.toml_config}")
|
||||
logging.info(f"trans_path: {self.trans_path}")
|
||||
logging.info(f"rel_urls: {self.rel_urls}")
|
||||
logging.info(f"log_path: {self.log_path}")
|
||||
if self.log_backups == 0:
|
||||
logging.info("log_backups: unlimited")
|
||||
else:
|
||||
logging.info(f"log_backups: {self.log_backups} days")
|
||||
self.log_level = self.get_log_level()
|
||||
logging.info('******')
|
||||
if self.log_level:
|
||||
# set lowest-severity for 'root', 'msg', 'conn' and 'data' logger
|
||||
logging.getLogger().setLevel(self.log_level)
|
||||
logging.getLogger('msg').setLevel(self.log_level)
|
||||
logging.getLogger('conn').setLevel(self.log_level)
|
||||
logging.getLogger('data').setLevel(self.log_level)
|
||||
logging.getLogger('tracer').setLevel(self.log_level)
|
||||
logging.getLogger('asyncio').setLevel(self.log_level)
|
||||
# logging.getLogger('mqtt').setLevel(self.log_level)
|
||||
|
||||
def build_config(self):
|
||||
# read config file
|
||||
Config.init(ConfigReadToml(self.src_dir + "cnf/default_config.toml"),
|
||||
log_path=self.log_path,
|
||||
cnf_path=self.config_path)
|
||||
ConfigReadEnv()
|
||||
ConfigReadJson(self.config_path + "config.json")
|
||||
ConfigReadToml(self.config_path + "config.toml")
|
||||
ConfigReadJson(self.json_config)
|
||||
ConfigReadToml(self.toml_config)
|
||||
config_err = Config.get_error()
|
||||
|
||||
if config_err is not None:
|
||||
logging.info(f'config_err: {config_err}')
|
||||
return
|
||||
|
||||
logging.info('******')
|
||||
|
||||
def get_log_level(self) -> int | None:
|
||||
'''checks if LOG_LVL is set in the environment and returns the
|
||||
corresponding logging.LOG_LEVEL'''
|
||||
switch = {
|
||||
'DEBUG': logging.DEBUG,
|
||||
'WARN': logging.WARNING,
|
||||
'INFO': logging.INFO,
|
||||
'ERROR': logging.ERROR,
|
||||
}
|
||||
log_lvl = os.getenv('LOG_LVL', None)
|
||||
logging.info(f"LOG_LVL : {log_lvl}")
|
||||
|
||||
return switch.get(log_lvl, None)
|
||||
routes = web.RouteTableDef()
|
||||
proxy_is_up = False
|
||||
|
||||
|
||||
class ProxyState:
|
||||
_is_up = False
|
||||
|
||||
@staticmethod
|
||||
def is_up() -> bool:
|
||||
return ProxyState._is_up
|
||||
|
||||
@staticmethod
|
||||
def set_up(value: bool):
|
||||
ProxyState._is_up = value
|
||||
@routes.get('/')
|
||||
async def hello(request):
|
||||
return web.Response(text="Hello, world")
|
||||
|
||||
|
||||
class HypercornLogHndl:
|
||||
access_hndl = []
|
||||
error_hndl = []
|
||||
must_fix = False
|
||||
HYPERC_ERR = 'hypercorn.error'
|
||||
HYPERC_ACC = 'hypercorn.access'
|
||||
|
||||
@classmethod
|
||||
def save(cls):
|
||||
cls.access_hndl = logging.getLogger(
|
||||
cls.HYPERC_ACC).handlers
|
||||
cls.error_hndl = logging.getLogger(
|
||||
cls.HYPERC_ERR).handlers
|
||||
cls.must_fix = True
|
||||
|
||||
@classmethod
|
||||
def restore(cls):
|
||||
if not cls.must_fix:
|
||||
return
|
||||
cls.must_fix = False
|
||||
access_hndl = logging.getLogger(
|
||||
cls.HYPERC_ACC).handlers
|
||||
if access_hndl != cls.access_hndl:
|
||||
print(' * Fix hypercorn.access setting')
|
||||
logging.getLogger(
|
||||
cls.HYPERC_ACC).handlers = cls.access_hndl
|
||||
|
||||
error_hndl = logging.getLogger(
|
||||
cls.HYPERC_ERR).handlers
|
||||
if error_hndl != cls.error_hndl:
|
||||
print(' * Fix hypercorn.error setting')
|
||||
logging.getLogger(
|
||||
cls.HYPERC_ERR).handlers = cls.error_hndl
|
||||
|
||||
|
||||
app = Quart(__name__,
|
||||
template_folder='web/templates',
|
||||
static_folder='web/static')
|
||||
app.secret_key = 'JKLdks.dajlKKKdladkflKwolafallsdfl'
|
||||
app.jinja_env.globals.update(url_for=url_for)
|
||||
app.background_tasks = set()
|
||||
server = Server(app, __name__ == "__main__")
|
||||
Web(app, server.trans_path, server.rel_urls)
|
||||
|
||||
|
||||
@app.route('/-/ready')
|
||||
async def ready():
|
||||
if ProxyState.is_up():
|
||||
@routes.get('/-/ready')
|
||||
async def ready(request):
|
||||
if proxy_is_up:
|
||||
status = 200
|
||||
text = 'Is ready'
|
||||
else:
|
||||
status = 503
|
||||
text = 'Not ready'
|
||||
return Response(status=status, response=text)
|
||||
return web.Response(status=status, text=text)
|
||||
|
||||
|
||||
@app.route('/-/healthy')
|
||||
async def healthy():
|
||||
@routes.get('/-/healthy')
|
||||
async def healthy(request):
|
||||
|
||||
if ProxyState.is_up():
|
||||
if proxy_is_up:
|
||||
# logging.info('web reqeust healthy()')
|
||||
for inverter in InverterIfc:
|
||||
try:
|
||||
res = inverter.healthy()
|
||||
if not res:
|
||||
return Response(status=503, response="I have a problem")
|
||||
return web.Response(status=503, text="I have a problem")
|
||||
except Exception as err:
|
||||
logging.info(f'Exception:{err}')
|
||||
|
||||
return Response(status=200, response="I'm fine")
|
||||
return web.Response(status=200, text="I'm fine")
|
||||
|
||||
|
||||
async def handle_client(reader: StreamReader,
|
||||
writer: StreamWriter,
|
||||
inv_class): # pragma: no cover
|
||||
async def webserver(addr, port):
|
||||
'''coro running our webserver'''
|
||||
app = web.Application()
|
||||
app.add_routes(routes)
|
||||
runner = web.AppRunner(app)
|
||||
|
||||
await runner.setup()
|
||||
site = web.TCPSite(runner, addr, port)
|
||||
await site.start()
|
||||
logging.info(f'HTTP server listen on port: {port}')
|
||||
|
||||
try:
|
||||
# Normal interaction with aiohttp
|
||||
while True:
|
||||
await asyncio.sleep(3600) # sleep forever
|
||||
except asyncio.CancelledError:
|
||||
logging.info('HTTP server cancelled')
|
||||
await runner.cleanup()
|
||||
logging.debug('HTTP cleanup done')
|
||||
|
||||
|
||||
async def handle_client(reader: StreamReader, writer: StreamWriter, inv_class):
|
||||
'''Handles a new incoming connection and starts an async loop'''
|
||||
|
||||
with inv_class(reader, writer) as inv:
|
||||
await inv.local.ifc.server_loop()
|
||||
|
||||
|
||||
@app.before_serving
|
||||
async def startup_app(): # pragma: no cover
|
||||
HypercornLogHndl.save()
|
||||
loop = asyncio.get_event_loop()
|
||||
Proxy.class_init()
|
||||
Schedule.start()
|
||||
ModbusTcp(loop)
|
||||
|
||||
for inv_class, port in [(InverterG3, 5005), (InverterG3P, 10000)]:
|
||||
logging.info(f'listen on port: {port} for inverters')
|
||||
task = loop.create_task(
|
||||
asyncio.start_server(lambda r, w, i=inv_class:
|
||||
handle_client(r, w, i),
|
||||
'0.0.0.0', port))
|
||||
app.background_tasks.add(task)
|
||||
task.add_done_callback(app.background_tasks.discard)
|
||||
|
||||
ProxyState.set_up(True)
|
||||
|
||||
|
||||
@app.before_request
|
||||
async def startup_request():
|
||||
HypercornLogHndl.restore()
|
||||
|
||||
|
||||
@app.after_serving
|
||||
async def handle_shutdown(): # pragma: no cover
|
||||
async def handle_shutdown(loop, web_task):
|
||||
'''Close all TCP connections and stop the event loop'''
|
||||
|
||||
logging.info('Shutdown due to SIGTERM')
|
||||
loop = asyncio.get_event_loop()
|
||||
ProxyState.set_up(False)
|
||||
global proxy_is_up
|
||||
proxy_is_up = False
|
||||
|
||||
#
|
||||
# first, disc all open TCP connections gracefully
|
||||
@@ -299,23 +96,149 @@ async def handle_shutdown(): # pragma: no cover
|
||||
await inverter.disc(True)
|
||||
|
||||
logging.info('Proxy disconnecting done')
|
||||
app.background_tasks.clear()
|
||||
|
||||
await Proxy.class_close(loop)
|
||||
#
|
||||
# second, cancel the web server
|
||||
#
|
||||
web_task.cancel()
|
||||
await web_task
|
||||
|
||||
#
|
||||
# now cancel all remaining (pending) tasks
|
||||
#
|
||||
pending = asyncio.all_tasks()
|
||||
for task in pending:
|
||||
task.cancel()
|
||||
|
||||
#
|
||||
# at last, start a coro for stopping the loop
|
||||
#
|
||||
logging.debug("Stop event loop")
|
||||
loop.stop()
|
||||
|
||||
|
||||
def get_log_level() -> int | None:
|
||||
'''checks if LOG_LVL is set in the environment and returns the
|
||||
corresponding logging.LOG_LEVEL'''
|
||||
switch = {
|
||||
'DEBUG': logging.DEBUG,
|
||||
'WARN': logging.WARNING,
|
||||
'INFO': logging.INFO,
|
||||
'ERROR': logging.ERROR,
|
||||
}
|
||||
log_level = os.getenv('LOG_LVL', None)
|
||||
logging.info(f"LOG_LVL : {log_level}")
|
||||
|
||||
return switch.get(log_level, None)
|
||||
|
||||
|
||||
def main(): # pragma: no cover
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-c', '--config_path', type=str,
|
||||
default='./config/',
|
||||
help='set path for the configuration files')
|
||||
parser.add_argument('-j', '--json_config', type=str,
|
||||
help='read user config from json-file')
|
||||
parser.add_argument('-t', '--toml_config', type=str,
|
||||
help='read user config from toml-file')
|
||||
parser.add_argument('-l', '--log_path', type=str,
|
||||
default='./log/',
|
||||
help='set path for the logging files')
|
||||
parser.add_argument('-b', '--log_backups', type=int,
|
||||
default=0,
|
||||
help='set max number of daily log-files')
|
||||
args = parser.parse_args()
|
||||
#
|
||||
# Setup our daily, rotating logger
|
||||
#
|
||||
serv_name = os.getenv('SERVICE_NAME', 'proxy')
|
||||
version = os.getenv('VERSION', 'unknown')
|
||||
|
||||
setattr(logging.handlers, "log_path", args.log_path)
|
||||
setattr(logging.handlers, "log_backups", args.log_backups)
|
||||
os.makedirs(args.log_path, exist_ok=True)
|
||||
|
||||
src_dir = os.path.dirname(__file__) + '/'
|
||||
logging.config.fileConfig(src_dir + 'logging.ini')
|
||||
logging.info(f'Server "{serv_name} - {version}" will be started')
|
||||
logging.info(f'current dir: {os.getcwd()}')
|
||||
logging.info(f"config_path: {args.config_path}")
|
||||
logging.info(f"json_config: {args.json_config}")
|
||||
logging.info(f"toml_config: {args.toml_config}")
|
||||
logging.info(f"log_path: {args.log_path}")
|
||||
if args.log_backups == 0:
|
||||
logging.info("log_backups: unlimited")
|
||||
else:
|
||||
logging.info(f"log_backups: {args.log_backups} days")
|
||||
log_level = get_log_level()
|
||||
logging.info('******')
|
||||
if log_level:
|
||||
# set lowest-severity for 'root', 'msg', 'conn' and 'data' logger
|
||||
logging.getLogger().setLevel(log_level)
|
||||
logging.getLogger('msg').setLevel(log_level)
|
||||
logging.getLogger('conn').setLevel(log_level)
|
||||
logging.getLogger('data').setLevel(log_level)
|
||||
logging.getLogger('tracer').setLevel(log_level)
|
||||
logging.getLogger('asyncio').setLevel(log_level)
|
||||
# logging.getLogger('mqtt').setLevel(log_level)
|
||||
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
|
||||
# read config file
|
||||
Config.init(ConfigReadToml(src_dir + "cnf/default_config.toml"))
|
||||
ConfigReadEnv()
|
||||
ConfigReadJson(args.config_path + "config.json")
|
||||
ConfigReadToml(args.config_path + "config.toml")
|
||||
ConfigReadJson(args.json_config)
|
||||
ConfigReadToml(args.toml_config)
|
||||
config_err = Config.get_error()
|
||||
|
||||
if config_err is not None:
|
||||
logging.info(f'config_err: {config_err}')
|
||||
return
|
||||
|
||||
logging.info('******')
|
||||
|
||||
Proxy.class_init()
|
||||
Schedule.start()
|
||||
ModbusTcp(loop)
|
||||
|
||||
#
|
||||
# Create tasks for our listening servers. These must be tasks! If we call
|
||||
# start_server directly out of our main task, the eventloop will be blocked
|
||||
# and we can't receive and handle the UNIX signals!
|
||||
#
|
||||
for inv_class, port in [(InverterG3, 5005), (InverterG3P, 10000)]:
|
||||
logging.info(f'listen on port: {port} for inverters')
|
||||
loop.create_task(asyncio.start_server(lambda r, w, i=inv_class:
|
||||
handle_client(r, w, i),
|
||||
'0.0.0.0', port))
|
||||
web_task = loop.create_task(webserver('0.0.0.0', 8127))
|
||||
|
||||
#
|
||||
# Register some UNIX Signal handler for a gracefully server shutdown
|
||||
# on Docker restart and stop
|
||||
#
|
||||
for signame in ('SIGINT', 'SIGTERM'):
|
||||
loop.add_signal_handler(getattr(signal, signame),
|
||||
lambda loop=loop: asyncio.create_task(
|
||||
handle_shutdown(loop, web_task)))
|
||||
|
||||
loop.set_debug(log_level == logging.DEBUG)
|
||||
try:
|
||||
global proxy_is_up
|
||||
proxy_is_up = True
|
||||
loop.run_forever()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
finally:
|
||||
logging.info("Event loop is stopped")
|
||||
Proxy.class_close(loop)
|
||||
logging.debug('Close event loop')
|
||||
loop.close()
|
||||
logging.info(f'Finally, exit Server "{serv_name}"')
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
|
||||
try:
|
||||
logging.info("Start Quart")
|
||||
app.run(host='0.0.0.0', port=8127, use_reloader=False,
|
||||
debug=server.log_level == logging.DEBUG)
|
||||
logging.info("Quart stopped")
|
||||
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
except asyncio.exceptions.CancelledError:
|
||||
logging.info("Quart cancelled")
|
||||
|
||||
finally:
|
||||
logging.info(f'Finally, exit Server "{server.serv_name}"')
|
||||
main()
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import mimetypes
|
||||
from importlib import import_module
|
||||
from pathlib import Path
|
||||
from collections.abc import Callable
|
||||
|
||||
|
||||
class SourceFileLoader:
|
||||
""" Represents a SouceFileLoader (__loader__)"""
|
||||
name: str
|
||||
get_resource_reader: Callable
|
||||
|
||||
|
||||
def load_modules(loader: SourceFileLoader):
|
||||
"""Load the entire modules from a SourceFileLoader (__loader__)"""
|
||||
pkg = loader.name
|
||||
for load in loader.get_resource_reader().contents():
|
||||
|
||||
if "python" not in str(mimetypes.guess_type(load)[0]):
|
||||
continue
|
||||
|
||||
mod = Path(load).stem
|
||||
if mod == "__init__":
|
||||
continue
|
||||
|
||||
import_module(pkg + "." + mod, pkg)
|
||||
@@ -1,32 +0,0 @@
|
||||
'''Quart blueprint for the proxy webserver with the dashboard
|
||||
|
||||
Usage:
|
||||
app = Quart(__name__, ...)
|
||||
Web(app)
|
||||
'''
|
||||
from quart import Quart, Blueprint
|
||||
from quart_babel import Babel
|
||||
from utils import load_modules
|
||||
|
||||
web = Blueprint('web', __name__)
|
||||
|
||||
load_modules(__loader__)
|
||||
|
||||
|
||||
class Web:
|
||||
'''Helper Class to register the Blueprint at Quart and
|
||||
initializing Babel'''
|
||||
def __init__(self,
|
||||
app: Quart,
|
||||
translation_directories: str | list[str],
|
||||
rel_urls: bool):
|
||||
web.build_relative_urls = rel_urls
|
||||
app.register_blueprint(web)
|
||||
|
||||
from .i18n import get_locale, get_tz
|
||||
global babel
|
||||
babel = Babel(
|
||||
app,
|
||||
locale_selector=get_locale,
|
||||
timezone_selector=get_tz,
|
||||
default_translation_directories=translation_directories)
|
||||
@@ -1,88 +0,0 @@
|
||||
from inverter_base import InverterBase
|
||||
from quart import render_template
|
||||
from quart_babel import format_datetime, _
|
||||
from infos import Infos
|
||||
|
||||
from . import web
|
||||
from .log_handler import LogHandler
|
||||
|
||||
|
||||
def _get_device_icon(client_mode: bool):
|
||||
'''returns the icon for the device conntection'''
|
||||
if client_mode:
|
||||
return 'fa-download fa-rotate-180', 'Server Mode'
|
||||
|
||||
return 'fa-upload fa-rotate-180', 'Client Mode'
|
||||
|
||||
|
||||
def _get_cloud_icon(emu_mode: bool):
|
||||
'''returns the icon for the cloud conntection'''
|
||||
if emu_mode:
|
||||
return 'fa-cloud-arrow-up-alt', 'Emu Mode'
|
||||
|
||||
return 'fa-cloud', 'Proxy Mode'
|
||||
|
||||
|
||||
def _get_row(inv: InverterBase):
|
||||
'''build one row for the connection table'''
|
||||
client_mode = inv.client_mode
|
||||
inv_serial = inv.local.stream.inv_serial
|
||||
icon1, descr1 = _get_device_icon(client_mode)
|
||||
ip1, port1 = inv.addr
|
||||
icon2 = ''
|
||||
descr2 = ''
|
||||
ip2 = '--'
|
||||
port2 = '--'
|
||||
|
||||
if inv.remote.ifc:
|
||||
ip2, port2 = inv.remote.ifc.r_addr
|
||||
icon2, descr2 = _get_cloud_icon(client_mode)
|
||||
|
||||
row = []
|
||||
row.append(f'<i class="fa {icon1}" title="{_(descr1)}"></i> {ip1}:{port1}')
|
||||
row.append(f'<i class="fa {icon1}" title="{_(descr1)}"></i> {ip1}')
|
||||
row.append(inv_serial)
|
||||
row.append(f'<i class="fa {icon2}" title="{_(descr2)}"></i> {ip2}:{port2}')
|
||||
row.append(f'<i class="fa {icon2}" title="{_(descr2)}"></i> {ip2}')
|
||||
return row
|
||||
|
||||
|
||||
def get_table_data():
|
||||
'''build the connection table'''
|
||||
table = {
|
||||
"headline": _('Connections'),
|
||||
"col_classes": [
|
||||
"w3-hide-small w3-hide-medium", "w3-hide-large",
|
||||
"",
|
||||
"w3-hide-small w3-hide-medium", "w3-hide-large",
|
||||
],
|
||||
"thead": [[
|
||||
_('Device-IP:Port'), _('Device-IP'),
|
||||
_("Serial-No"),
|
||||
_("Cloud-IP:Port"), _("Cloud-IP")
|
||||
]],
|
||||
"tbody": []
|
||||
}
|
||||
for inverter in InverterBase:
|
||||
table['tbody'].append(_get_row(inverter))
|
||||
|
||||
return table
|
||||
|
||||
|
||||
@web.route('/data-fetch')
|
||||
async def data_fetch():
|
||||
data = {
|
||||
"update-time": format_datetime(format="medium"),
|
||||
"server-cnt": f"<h3>{Infos.get_counter('ServerMode_Cnt')}</h3>",
|
||||
"client-cnt": f"<h3>{Infos.get_counter('ClientMode_Cnt')}</h3>",
|
||||
"proxy-cnt": f"<h3>{Infos.get_counter('ProxyMode_Cnt')}</h3>",
|
||||
"emulation-cnt": f"<h3>{Infos.get_counter('EmuMode_Cnt')}</h3>",
|
||||
}
|
||||
data["conn-table"] = await render_template('templ_table.html.j2',
|
||||
table=get_table_data())
|
||||
|
||||
data["notes-list"] = await render_template(
|
||||
'templ_notes_list.html.j2',
|
||||
notes=LogHandler().get_buffer(3),
|
||||
hide_if_empty=True)
|
||||
return data
|
||||
@@ -1,37 +0,0 @@
|
||||
import os
|
||||
|
||||
from quart import send_from_directory
|
||||
|
||||
from . import web
|
||||
|
||||
|
||||
async def get_icon(file: str, mime: str = 'image/png'):
|
||||
return await send_from_directory(
|
||||
os.path.join(web.root_path, 'static/images'),
|
||||
file,
|
||||
mimetype=mime)
|
||||
|
||||
|
||||
@web.route('/favicon-96x96.png')
|
||||
async def favicon():
|
||||
return await get_icon('favicon-96x96.png')
|
||||
|
||||
|
||||
@web.route('/favicon.ico')
|
||||
async def favicon_ico():
|
||||
return await get_icon('favicon.ico', 'image/x-icon')
|
||||
|
||||
|
||||
@web.route('/favicon.svg')
|
||||
async def favicon_svg():
|
||||
return await get_icon('favicon.svg', 'image/svg+xml')
|
||||
|
||||
|
||||
@web.route('/apple-touch-icon.png')
|
||||
async def apple_touch():
|
||||
return await get_icon('apple-touch-icon.png')
|
||||
|
||||
|
||||
@web.route('/site.webmanifest')
|
||||
async def webmanifest():
|
||||
return await get_icon('site.webmanifest', 'application/manifest+json')
|
||||
@@ -1,45 +0,0 @@
|
||||
from quart import request, session, redirect, abort
|
||||
from quart_babel.locale import get_locale as babel_get_locale
|
||||
|
||||
from . import web
|
||||
|
||||
LANGUAGES = {
|
||||
'en': 'English',
|
||||
'de': 'Deutsch',
|
||||
# 'fr': 'Français'
|
||||
}
|
||||
|
||||
|
||||
def get_locale():
|
||||
try:
|
||||
language = session['language']
|
||||
except KeyError:
|
||||
language = None
|
||||
if language is not None:
|
||||
return language
|
||||
|
||||
# check how to get the locale form for the add-on - hass.selectedLanguage
|
||||
# logging.info("get_locale(%s)", request.accept_languages)
|
||||
return request.accept_languages.best_match(LANGUAGES.keys())
|
||||
|
||||
|
||||
def get_tz():
|
||||
return 'CET'
|
||||
|
||||
|
||||
@web.context_processor
|
||||
def utility_processor():
|
||||
return {'lang': babel_get_locale(),
|
||||
'lang_str': LANGUAGES.get(str(babel_get_locale()), "English"),
|
||||
'languages': LANGUAGES}
|
||||
|
||||
|
||||
@web.route('/language/<language>')
|
||||
async def set_language(language=None):
|
||||
if language in LANGUAGES:
|
||||
session['language'] = language
|
||||
|
||||
rsp = redirect(request.referrer if request.referrer else '../#')
|
||||
rsp.content_language = language
|
||||
return rsp
|
||||
return abort(404)
|
||||
@@ -1,92 +0,0 @@
|
||||
from quart import render_template
|
||||
from quart_babel import format_datetime, format_decimal, _
|
||||
from quart.helpers import send_from_directory
|
||||
from werkzeug.utils import secure_filename
|
||||
from cnf.config import Config
|
||||
from datetime import datetime
|
||||
from os import DirEntry
|
||||
import os
|
||||
from dateutil import tz
|
||||
|
||||
from . import web
|
||||
|
||||
|
||||
def _get_birth_from_log(path: str) -> None | datetime:
|
||||
'''read timestamp from the first line of a log file'''
|
||||
dt = None
|
||||
try:
|
||||
with open(path) as f:
|
||||
first_line = f.readline()
|
||||
first_line = first_line.lstrip("'")
|
||||
fmt = "%Y-%m-%d %H:%M:%S" if first_line[4] == '-' \
|
||||
else "%d-%m-%Y %H:%M:%S"
|
||||
dt = datetime.strptime(first_line[0:19], fmt). \
|
||||
replace(tzinfo=tz.tzlocal())
|
||||
except Exception:
|
||||
pass
|
||||
return dt
|
||||
|
||||
|
||||
def _get_file(file: DirEntry) -> dict:
|
||||
'''build one row for the connection table'''
|
||||
entry = {}
|
||||
entry['name'] = file.name
|
||||
stat = file.stat()
|
||||
entry['size'] = format_decimal(stat.st_size)
|
||||
try:
|
||||
dt = stat.st_birthtime
|
||||
|
||||
except Exception:
|
||||
dt = _get_birth_from_log(file.path)
|
||||
|
||||
if dt:
|
||||
entry['created'] = format_datetime(dt, format="short")
|
||||
|
||||
# sort by creating date, if available
|
||||
entry['date'] = dt if isinstance(dt, float) else dt.timestamp()
|
||||
else:
|
||||
entry['created'] = _('n/a')
|
||||
entry['date'] = stat.st_mtime
|
||||
|
||||
entry['modified'] = format_datetime(stat.st_mtime, format="short")
|
||||
return entry
|
||||
|
||||
|
||||
def get_list_data() -> list:
|
||||
'''build the connection table'''
|
||||
file_list = []
|
||||
with os.scandir(Config.get_log_path()) as it:
|
||||
for entry in it:
|
||||
if entry.is_file():
|
||||
file_list.append(_get_file(entry))
|
||||
|
||||
file_list.sort(key=lambda x: x['date'], reverse=True)
|
||||
return file_list
|
||||
|
||||
|
||||
@web.route('/file-fetch')
|
||||
async def file_fetch():
|
||||
data = {
|
||||
"update-time": format_datetime(format="medium"),
|
||||
}
|
||||
data["file-list"] = await render_template('templ_log_files_list.html.j2',
|
||||
dir_list=get_list_data())
|
||||
|
||||
return data
|
||||
|
||||
|
||||
@web.route('/send-file/<file>')
|
||||
async def send(file):
|
||||
return await send_from_directory(
|
||||
directory=Config.get_log_path(),
|
||||
file_name=secure_filename(file),
|
||||
as_attachment=True)
|
||||
|
||||
|
||||
@web.route('/del-file/<file>', methods=['DELETE'])
|
||||
async def delete(file):
|
||||
try:
|
||||
os.remove(Config.get_log_path() + secure_filename(file))
|
||||
except OSError:
|
||||
return 'File not found', 404
|
||||
return '', 204
|
||||
@@ -1,27 +0,0 @@
|
||||
from logging import Handler
|
||||
from logging import LogRecord
|
||||
import logging
|
||||
from collections import deque
|
||||
|
||||
from singleton import Singleton
|
||||
|
||||
|
||||
class LogHandler(Handler, metaclass=Singleton):
|
||||
def __init__(self, capacity=64):
|
||||
super().__init__(logging.WARNING)
|
||||
self.capacity = capacity
|
||||
self.buffer = deque(maxlen=capacity)
|
||||
|
||||
def emit(self, record: LogRecord):
|
||||
self.buffer.append({
|
||||
'ctime': record.created,
|
||||
'level': record.levelno,
|
||||
'lname': record.levelname,
|
||||
'msg': record.getMessage()
|
||||
})
|
||||
|
||||
def get_buffer(self, elms=0) -> list:
|
||||
return list(self.buffer)[-elms:]
|
||||
|
||||
def clear(self):
|
||||
self.buffer.clear()
|
||||
@@ -1,67 +0,0 @@
|
||||
from inverter_base import InverterBase
|
||||
from quart import render_template
|
||||
from quart_babel import format_datetime, _
|
||||
from mqtt import Mqtt
|
||||
|
||||
from . import web
|
||||
from .log_handler import LogHandler
|
||||
|
||||
|
||||
def _get_row(inv: InverterBase):
|
||||
'''build one row for the connection table'''
|
||||
entity_prfx = inv.entity_prfx
|
||||
inv_serial = inv.local.stream.inv_serial
|
||||
node_id = inv.local.stream.node_id
|
||||
sug_area = inv.local.stream.sug_area
|
||||
|
||||
row = []
|
||||
row.append(inv_serial)
|
||||
row.append(entity_prfx+node_id)
|
||||
row.append(sug_area)
|
||||
return row
|
||||
|
||||
|
||||
def get_table_data():
|
||||
'''build the connection table'''
|
||||
table = {
|
||||
"headline": _('MQTT devices'),
|
||||
"col_classes": [
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
],
|
||||
"thead": [[
|
||||
_("Serial-No"),
|
||||
_('Node-ID'),
|
||||
_('HA-Area'),
|
||||
]],
|
||||
"tbody": []
|
||||
}
|
||||
for inverter in InverterBase:
|
||||
table['tbody'].append(_get_row(inverter))
|
||||
|
||||
return table
|
||||
|
||||
|
||||
@web.route('/mqtt-fetch')
|
||||
async def mqtt_fetch():
|
||||
mqtt = Mqtt(None)
|
||||
cdatetime = format_datetime(dt=mqtt.ctime, format='d.MM. HH:mm')
|
||||
data = {
|
||||
"update-time": format_datetime(format="medium"),
|
||||
"mqtt-ctime": f"""
|
||||
<h3 class="w3-hide-small w3-hide-medium">{cdatetime}</h3>
|
||||
<h4 class="w3-hide-large">{cdatetime}</h4>
|
||||
""",
|
||||
"mqtt-tx": f"<h3>{mqtt.published}</h3>",
|
||||
"mqtt-rx": f"<h3>{mqtt.received}</h3>",
|
||||
}
|
||||
data["mqtt-table"] = await render_template('templ_table.html.j2',
|
||||
table=get_table_data())
|
||||
|
||||
data["notes-list"] = await render_template(
|
||||
'templ_notes_list.html.j2',
|
||||
notes=LogHandler().get_buffer(3),
|
||||
hide_if_empty=True)
|
||||
|
||||
return data
|
||||
@@ -1,19 +0,0 @@
|
||||
from quart import render_template
|
||||
from quart_babel import format_datetime
|
||||
|
||||
from . import web
|
||||
from .log_handler import LogHandler
|
||||
|
||||
|
||||
@web.route('/notes-fetch')
|
||||
async def notes_fetch():
|
||||
data = {
|
||||
"update-time": format_datetime(format="medium"),
|
||||
}
|
||||
|
||||
data["notes-list"] = await render_template(
|
||||
'templ_notes_list.html.j2',
|
||||
notes=LogHandler().get_buffer(),
|
||||
hide_if_empty=False)
|
||||
|
||||
return data
|
||||
@@ -1,32 +0,0 @@
|
||||
from quart import render_template
|
||||
from .wrapper import url_for
|
||||
|
||||
from . import web
|
||||
|
||||
|
||||
@web.route('/')
|
||||
async def index():
|
||||
return await render_template(
|
||||
'page_index.html.j2',
|
||||
fetch_url=url_for('.data_fetch'))
|
||||
|
||||
|
||||
@web.route('/mqtt')
|
||||
async def mqtt():
|
||||
return await render_template(
|
||||
'page_mqtt.html.j2',
|
||||
fetch_url=url_for('.mqtt_fetch'))
|
||||
|
||||
|
||||
@web.route('/notes')
|
||||
async def notes():
|
||||
return await render_template(
|
||||
'page_notes.html.j2',
|
||||
fetch_url=url_for('.notes_fetch'))
|
||||
|
||||
|
||||
@web.route('/logging')
|
||||
async def logging():
|
||||
return await render_template(
|
||||
'page_logging.html.j2',
|
||||
fetch_url=url_for('.file_fetch'))
|
||||
@@ -1,251 +0,0 @@
|
||||
/* W3.CSS 5.02 March 31 2025 by Jan Egil and Borge Refsnes */
|
||||
html{box-sizing:border-box;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;overflow-x:hidden}*,*:before,*:after{box-sizing:inherit}
|
||||
/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */
|
||||
body{margin:0}
|
||||
article,aside,details,figcaption,figure,footer,header,main,menu,nav,section{display:block}summary{display:list-item}
|
||||
audio,canvas,progress,video{display:inline-block}progress{vertical-align:baseline}
|
||||
audio:not([controls]){display:none;height:0}[hidden],template{display:none}
|
||||
a{background-color:transparent;color:inherit}
|
||||
a:active,a:hover{outline-width:0}
|
||||
abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}
|
||||
b,strong{font-weight:bolder}dfn{font-style:italic}mark{background:#ff0;color:#000}
|
||||
small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
|
||||
sub{bottom:-0.25em}sup{top:-0.5em}figure{margin:1em 40px}
|
||||
code,kbd,pre,samp{font-family:monospace;font-size:1em}
|
||||
button,input,select,textarea,optgroup{font:inherit;margin:0}optgroup{font-weight:bold}
|
||||
button,input{overflow:visible}button,select{text-transform:none}
|
||||
button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button;appearance:button}
|
||||
button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0}
|
||||
button:-moz-focusring,[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring{outline:1px dotted ButtonText}
|
||||
fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:.35em .625em .75em}
|
||||
legend{color:inherit;display:table;max-width:100%;padding:0;white-space:normal}textarea{overflow:auto}
|
||||
[type=checkbox],[type=radio]{padding:0}
|
||||
[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}
|
||||
[type=search]{-webkit-appearance:textfield;appearance:textfoeld;outline-offset:-2px}
|
||||
[type=search]::-webkit-search-decoration{-webkit-appearance:none}
|
||||
::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}
|
||||
/* End extract */
|
||||
html,body{font-family:Verdana,sans-serif;font-size:15px;line-height:1.5}
|
||||
h1{font-size:36px}h2{font-size:30px}h3{font-size:24px}h4{font-size:20px}h5{font-size:18px}h6{font-size:16px}
|
||||
.w3-serif{font-family:serif}.w3-sans-serif{font-family:sans-serif}.w3-cursive{font-family:cursive}.w3-monospace{font-family:monospace}
|
||||
h1,h2,h3,h4,h5,h6{font-family:"Segoe UI",Arial,sans-serif;font-weight:400;margin:10px 0}.w3-wide{letter-spacing:4px}
|
||||
hr{box-sizing:content-box;height:0;overflow:visible;border:0;border-top:1px solid #eee;margin:20px 0}
|
||||
.w3-image{max-width:100%;height:auto}img{border-style:none;vertical-align:middle}
|
||||
.w3-table,.w3-table-all{border-collapse:collapse;border-spacing:0;width:100%;display:table}.w3-table-all{border:1px solid #ccc}
|
||||
.w3-bordered tr,.w3-table-all tr{border-bottom:1px solid #ddd}.w3-striped tbody tr:nth-child(even){background-color:#f1f1f1}
|
||||
.w3-table-all tr:nth-child(odd){background-color:#fff}.w3-table-all tr:nth-child(even){background-color:#f1f1f1}
|
||||
.w3-hoverable tbody tr:hover,.w3-ul.w3-hoverable li:hover{background-color:#ccc}.w3-centered tr th,.w3-centered tr td{text-align:center}
|
||||
.w3-table td,.w3-table th,.w3-table-all td,.w3-table-all th{padding:8px 8px;display:table-cell;text-align:left;vertical-align:top}
|
||||
.w3-table th:first-child,.w3-table td:first-child,.w3-table-all th:first-child,.w3-table-all td:first-child{padding-left:16px}
|
||||
.w3-btn,.w3-button{border:none;display:inline-block;padding:8px 16px;vertical-align:middle;overflow:hidden;text-decoration:none;color:inherit;background-color:inherit;text-align:center;cursor:pointer;white-space:nowrap;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
|
||||
.w3-btn:hover{box-shadow:0 8px 16px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19)}
|
||||
.w3-disabled,.w3-btn:disabled,.w3-button:disabled{cursor:not-allowed;opacity:0.3}.w3-disabled *,:disabled *{pointer-events:none}
|
||||
.w3-btn.w3-disabled:hover,.w3-btn:disabled:hover{box-shadow:none}
|
||||
.w3-badge,.w3-tag{background-color:#000;color:#fff;display:inline-block;padding-left:8px;padding-right:8px;text-align:center}.w3-badge{border-radius:50%}
|
||||
.w3-ul{list-style-type:none;padding:0;margin:0}.w3-ul li{padding:8px 16px;border-bottom:1px solid #ddd}.w3-ul li:last-child{border-bottom:none}
|
||||
.w3-tooltip,.w3-display-container{position:relative}.w3-tooltip .w3-text{display:none}.w3-tooltip:hover .w3-text{display:inline-block}
|
||||
.w3-ripple:active{opacity:0.5}.w3-ripple{transition:opacity 0s}
|
||||
.w3-input{padding:8px;display:block;border:none;border-bottom:1px solid #ccc;width:100%}
|
||||
.w3-select{padding:9px 0;width:100%;border:none;border-bottom:1px solid #ccc}
|
||||
.w3-dropdown-click,.w3-dropdown-hover{position:relative;display:inline-block;cursor:pointer}
|
||||
.w3-dropdown-hover:hover .w3-dropdown-content{display:block}
|
||||
.w3-dropdown-hover:first-child,.w3-dropdown-click:hover{background-color:#ccc;color:#000}
|
||||
.w3-dropdown-hover:hover > .w3-button:first-child,.w3-dropdown-click:hover > .w3-button:first-child{background-color:#ccc;color:#000}
|
||||
.w3-dropdown-content{cursor:auto;color:#000;background-color:#fff;display:none;position:absolute;min-width:160px;margin:0;padding:0;z-index:1}
|
||||
.w3-check,.w3-radio{width:24px;height:24px;position:relative;top:6px}
|
||||
.w3-sidebar{height:100%;width:200px;background-color:#fff;position:fixed!important;z-index:1;overflow:auto}
|
||||
.w3-bar-block .w3-dropdown-hover,.w3-bar-block .w3-dropdown-click{width:100%}
|
||||
.w3-bar-block .w3-dropdown-hover .w3-dropdown-content,.w3-bar-block .w3-dropdown-click .w3-dropdown-content{min-width:100%}
|
||||
.w3-bar-block .w3-dropdown-hover .w3-button,.w3-bar-block .w3-dropdown-click .w3-button{width:100%;text-align:left;padding:8px 16px}
|
||||
.w3-main,#main{transition:margin-left .4s}
|
||||
.w3-modal{z-index:3;display:none;padding-top:100px;position:fixed;left:0;top:0;width:100%;height:100%;overflow:auto;background-color:rgb(0,0,0);background-color:rgba(0,0,0,0.4)}
|
||||
.w3-modal-content{margin:auto;background-color:#fff;position:relative;padding:0;outline:0;width:600px}
|
||||
.w3-bar{width:100%;overflow:hidden}.w3-center .w3-bar{display:inline-block;width:auto}
|
||||
.w3-bar .w3-bar-item{padding:8px 16px;float:left;width:auto;border:none;display:block;outline:0}
|
||||
.w3-bar .w3-dropdown-hover,.w3-bar .w3-dropdown-click{position:static;float:left}
|
||||
.w3-bar .w3-button{white-space:normal}
|
||||
.w3-bar-block .w3-bar-item{width:100%;display:block;padding:8px 16px;text-align:left;border:none;white-space:normal;float:none;outline:0}
|
||||
.w3-bar-block.w3-center .w3-bar-item{text-align:center}.w3-block{display:block;width:100%}
|
||||
.w3-responsive{display:block;overflow-x:auto}
|
||||
.w3-container:after,.w3-container:before,.w3-panel:after,.w3-panel:before,.w3-row:after,.w3-row:before,.w3-row-padding:after,.w3-row-padding:before,
|
||||
.w3-cell-row:before,.w3-cell-row:after,.w3-clear:after,.w3-clear:before,.w3-bar:before,.w3-bar:after{content:"";display:table;clear:both}
|
||||
.w3-col,.w3-half,.w3-third,.w3-twothird,.w3-threequarter,.w3-quarter{float:left;width:100%}
|
||||
.w3-col.s1{width:8.33333%}.w3-col.s2{width:16.66666%}.w3-col.s3{width:24.99999%}.w3-col.s4{width:33.33333%}
|
||||
.w3-col.s5{width:41.66666%}.w3-col.s6{width:49.99999%}.w3-col.s7{width:58.33333%}.w3-col.s8{width:66.66666%}
|
||||
.w3-col.s9{width:74.99999%}.w3-col.s10{width:83.33333%}.w3-col.s11{width:91.66666%}.w3-col.s12{width:99.99999%}
|
||||
@media (min-width:601px){.w3-col.m1{width:8.33333%}.w3-col.m2{width:16.66666%}.w3-col.m3,.w3-quarter{width:24.99999%}.w3-col.m4,.w3-third{width:33.33333%}
|
||||
.w3-col.m5{width:41.66666%}.w3-col.m6,.w3-half{width:49.99999%}.w3-col.m7{width:58.33333%}.w3-col.m8,.w3-twothird{width:66.66666%}
|
||||
.w3-col.m9,.w3-threequarter{width:74.99999%}.w3-col.m10{width:83.33333%}.w3-col.m11{width:91.66666%}.w3-col.m12{width:99.99999%}}
|
||||
@media (min-width:993px){.w3-col.l1{width:8.33333%}.w3-col.l2{width:16.66666%}.w3-col.l3{width:24.99999%}.w3-col.l4{width:33.33333%}
|
||||
.w3-col.l5{width:41.66666%}.w3-col.l6{width:49.99999%}.w3-col.l7{width:58.33333%}.w3-col.l8{width:66.66666%}
|
||||
.w3-col.l9{width:74.99999%}.w3-col.l10{width:83.33333%}.w3-col.l11{width:91.66666%}.w3-col.l12{width:99.99999%}}
|
||||
.w3-rest{overflow:hidden}.w3-stretch{margin-left:-16px;margin-right:-16px}
|
||||
.w3-content,.w3-auto{margin-left:auto;margin-right:auto}.w3-content{max-width:980px}.w3-auto{max-width:1140px}
|
||||
.w3-cell-row{display:table;width:100%}.w3-cell{display:table-cell}
|
||||
.w3-cell-top{vertical-align:top}.w3-cell-middle{vertical-align:middle}.w3-cell-bottom{vertical-align:bottom}
|
||||
.w3-hide{display:none!important}.w3-show-block,.w3-show{display:block!important}.w3-show-inline-block{display:inline-block!important}
|
||||
@media (max-width:1205px){.w3-auto{max-width:95%}}
|
||||
@media (max-width:600px){.w3-modal-content{margin:0 10px;width:auto!important}.w3-modal{padding-top:30px}
|
||||
.w3-dropdown-hover.w3-mobile .w3-dropdown-content,.w3-dropdown-click.w3-mobile .w3-dropdown-content{position:relative}
|
||||
.w3-hide-small{display:none!important}.w3-mobile{display:block;width:100%!important}.w3-bar-item.w3-mobile,.w3-dropdown-hover.w3-mobile,.w3-dropdown-click.w3-mobile{text-align:center}
|
||||
.w3-dropdown-hover.w3-mobile,.w3-dropdown-hover.w3-mobile .w3-btn,.w3-dropdown-hover.w3-mobile .w3-button,.w3-dropdown-click.w3-mobile,.w3-dropdown-click.w3-mobile .w3-btn,.w3-dropdown-click.w3-mobile .w3-button{width:100%}}
|
||||
@media (max-width:768px){.w3-modal-content{width:500px}.w3-modal{padding-top:50px}}
|
||||
@media (min-width:993px){.w3-modal-content{width:900px}.w3-hide-large{display:none!important}.w3-sidebar.w3-collapse{display:block!important}}
|
||||
@media (max-width:992px) and (min-width:601px){.w3-hide-medium{display:none!important}}
|
||||
@media (max-width:992px){.w3-sidebar.w3-collapse{display:none}.w3-main{margin-left:0!important;margin-right:0!important}.w3-auto{max-width:100%}}
|
||||
.w3-top,.w3-bottom{position:fixed;width:100%;z-index:1}.w3-top{top:0}.w3-bottom{bottom:0}
|
||||
.w3-overlay{position:fixed;display:none;width:100%;height:100%;top:0;left:0;right:0;bottom:0;background-color:rgba(0,0,0,0.5);z-index:2}
|
||||
.w3-display-topleft{position:absolute;left:0;top:0}.w3-display-topright{position:absolute;right:0;top:0}
|
||||
.w3-display-bottomleft{position:absolute;left:0;bottom:0}.w3-display-bottomright{position:absolute;right:0;bottom:0}
|
||||
.w3-display-middle{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%)}
|
||||
.w3-display-left{position:absolute;top:50%;left:0%;transform:translate(0%,-50%);-ms-transform:translate(-0%,-50%)}
|
||||
.w3-display-right{position:absolute;top:50%;right:0%;transform:translate(0%,-50%);-ms-transform:translate(0%,-50%)}
|
||||
.w3-display-topmiddle{position:absolute;left:50%;top:0;transform:translate(-50%,0%);-ms-transform:translate(-50%,0%)}
|
||||
.w3-display-bottommiddle{position:absolute;left:50%;bottom:0;transform:translate(-50%,0%);-ms-transform:translate(-50%,0%)}
|
||||
.w3-display-container:hover .w3-display-hover{display:block}.w3-display-container:hover span.w3-display-hover{display:inline-block}.w3-display-hover{display:none}
|
||||
.w3-display-position{position:absolute}
|
||||
.w3-circle{border-radius:50%}
|
||||
.w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px}
|
||||
.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px}
|
||||
.w3-container,.w3-panel{padding:0.01em 16px}.w3-panel{margin-top:16px;margin-bottom:16px}
|
||||
.w3-grid{display:grid}.w3-grid-padding{display:grid;gap:16px}.w3-flex{display:flex}
|
||||
.w3-text-center{text-align:center}.w3-text-bold,.w3-bold{font-weight:bold}.w3-text-italic,.w3-italic{font-style:italic}
|
||||
.w3-code,.w3-codespan{font-family:Consolas,"courier new",monospace;font-size:16px}
|
||||
.w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word}
|
||||
.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%}
|
||||
.w3-card,.w3-card-2{box-shadow:0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12)}
|
||||
.w3-card-4,.w3-hover-shadow:hover{box-shadow:0 4px 10px 0 rgba(0,0,0,0.2),0 4px 20px 0 rgba(0,0,0,0.19)}
|
||||
.w3-spin{animation:w3-spin 2s infinite linear}@keyframes w3-spin{0%{transform:rotate(0deg)}100%{transform:rotate(359deg)}}
|
||||
.w3-animate-fading{animation:fading 10s infinite}@keyframes fading{0%{opacity:0}50%{opacity:1}100%{opacity:0}}
|
||||
.w3-animate-opacity{animation:opac 0.8s}@keyframes opac{from{opacity:0} to{opacity:1}}
|
||||
.w3-animate-top{position:relative;animation:animatetop 0.4s}@keyframes animatetop{from{top:-300px;opacity:0} to{top:0;opacity:1}}
|
||||
.w3-animate-left{position:relative;animation:animateleft 0.4s}@keyframes animateleft{from{left:-300px;opacity:0} to{left:0;opacity:1}}
|
||||
.w3-animate-right{position:relative;animation:animateright 0.4s}@keyframes animateright{from{right:-300px;opacity:0} to{right:0;opacity:1}}
|
||||
.w3-animate-bottom{position:relative;animation:animatebottom 0.4s}@keyframes animatebottom{from{bottom:-300px;opacity:0} to{bottom:0;opacity:1}}
|
||||
.w3-animate-zoom {animation:animatezoom 0.6s}@keyframes animatezoom{from{transform:scale(0)} to{transform:scale(1)}}
|
||||
.w3-animate-input{transition:width 0.4s ease-in-out}.w3-animate-input:focus{width:100%!important}
|
||||
.w3-opacity,.w3-hover-opacity:hover{opacity:0.60}.w3-opacity-off,.w3-hover-opacity-off:hover{opacity:1}
|
||||
.w3-opacity-max{opacity:0.25}.w3-opacity-min{opacity:0.75}
|
||||
.w3-greyscale-max,.w3-grayscale-max,.w3-hover-greyscale:hover,.w3-hover-grayscale:hover{filter:grayscale(100%)}
|
||||
.w3-greyscale,.w3-grayscale{filter:grayscale(75%)}.w3-greyscale-min,.w3-grayscale-min{filter:grayscale(50%)}
|
||||
.w3-sepia{filter:sepia(75%)}.w3-sepia-max,.w3-hover-sepia:hover{filter:sepia(100%)}.w3-sepia-min{filter:sepia(50%)}
|
||||
.w3-tiny{font-size:10px!important}.w3-small{font-size:12px!important}.w3-medium{font-size:15px!important}.w3-large{font-size:18px!important}
|
||||
.w3-xlarge{font-size:24px!important}.w3-xxlarge{font-size:36px!important}.w3-xxxlarge{font-size:48px!important}.w3-jumbo{font-size:64px!important}
|
||||
.w3-left-align{text-align:left!important}.w3-right-align{text-align:right!important}.w3-justify{text-align:justify!important}.w3-center{text-align:center!important}
|
||||
.w3-border-0{border:0!important}.w3-border{border:1px solid #ccc!important}
|
||||
.w3-border-top{border-top:1px solid #ccc!important}.w3-border-bottom{border-bottom:1px solid #ccc!important}
|
||||
.w3-border-left{border-left:1px solid #ccc!important}.w3-border-right{border-right:1px solid #ccc!important}
|
||||
.w3-topbar{border-top:6px solid #ccc!important}.w3-bottombar{border-bottom:6px solid #ccc!important}
|
||||
.w3-leftbar{border-left:6px solid #ccc!important}.w3-rightbar{border-right:6px solid #ccc!important}
|
||||
.w3-section,.w3-code{margin-top:16px!important;margin-bottom:16px!important}
|
||||
.w3-margin{margin:16px!important}.w3-margin-top{margin-top:16px!important}.w3-margin-bottom{margin-bottom:16px!important}
|
||||
.w3-margin-left{margin-left:16px!important}.w3-margin-right{margin-right:16px!important}
|
||||
.w3-padding-small{padding:4px 8px!important}.w3-padding{padding:8px 16px!important}.w3-padding-large{padding:12px 24px!important}
|
||||
.w3-padding-16{padding-top:16px!important;padding-bottom:16px!important}.w3-padding-24{padding-top:24px!important;padding-bottom:24px!important}
|
||||
.w3-padding-32{padding-top:32px!important;padding-bottom:32px!important}.w3-padding-48{padding-top:48px!important;padding-bottom:48px!important}
|
||||
.w3-padding-64{padding-top:64px!important;padding-bottom:64px!important}
|
||||
.w3-padding-top-64{padding-top:64px!important}.w3-padding-top-48{padding-top:48px!important}
|
||||
.w3-padding-top-32{padding-top:32px!important}.w3-padding-top-24{padding-top:24px!important}
|
||||
.w3-left{float:left!important}.w3-right{float:right!important}
|
||||
.w3-button:hover{color:#000!important;background-color:#ccc!important}
|
||||
.w3-transparent,.w3-hover-none:hover{background-color:transparent!important}
|
||||
.w3-hover-none:hover{box-shadow:none!important}
|
||||
.w3-rtl{direction:rtl}.w3-ltr{direction:ltr}
|
||||
/* Colors */
|
||||
.w3-amber,.w3-hover-amber:hover{color:#000!important;background-color:#ffc107!important}
|
||||
.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important}
|
||||
.w3-blue,.w3-hover-blue:hover{color:#fff!important;background-color:#2196F3!important}
|
||||
.w3-light-blue,.w3-hover-light-blue:hover{color:#000!important;background-color:#87CEEB!important}
|
||||
.w3-brown,.w3-hover-brown:hover{color:#fff!important;background-color:#795548!important}
|
||||
.w3-cyan,.w3-hover-cyan:hover{color:#000!important;background-color:#00bcd4!important}
|
||||
.w3-blue-grey,.w3-hover-blue-grey:hover,.w3-blue-gray,.w3-hover-blue-gray:hover{color:#fff!important;background-color:#607d8b!important}
|
||||
.w3-green,.w3-hover-green:hover{color:#fff!important;background-color:#4CAF50!important}
|
||||
.w3-light-green,.w3-hover-light-green:hover{color:#000!important;background-color:#8bc34a!important}
|
||||
.w3-indigo,.w3-hover-indigo:hover{color:#fff!important;background-color:#3f51b5!important}
|
||||
.w3-khaki,.w3-hover-khaki:hover{color:#000!important;background-color:#f0e68c!important}
|
||||
.w3-lime,.w3-hover-lime:hover{color:#000!important;background-color:#cddc39!important}
|
||||
.w3-orange,.w3-hover-orange:hover{color:#000!important;background-color:#ff9800!important}
|
||||
.w3-deep-orange,.w3-hover-deep-orange:hover{color:#fff!important;background-color:#ff5722!important}
|
||||
.w3-pink,.w3-hover-pink:hover{color:#fff!important;background-color:#e91e63!important}
|
||||
.w3-purple,.w3-hover-purple:hover{color:#fff!important;background-color:#9c27b0!important}
|
||||
.w3-deep-purple,.w3-hover-deep-purple:hover{color:#fff!important;background-color:#673ab7!important}
|
||||
.w3-red,.w3-hover-red:hover{color:#fff!important;background-color:#f44336!important}
|
||||
.w3-sand,.w3-hover-sand:hover{color:#000!important;background-color:#fdf5e6!important}
|
||||
.w3-teal,.w3-hover-teal:hover{color:#fff!important;background-color:#009688!important}
|
||||
.w3-yellow,.w3-hover-yellow:hover{color:#000!important;background-color:#ffeb3b!important}
|
||||
.w3-white,.w3-hover-white:hover{color:#000!important;background-color:#fff!important}
|
||||
.w3-black,.w3-hover-black:hover{color:#fff!important;background-color:#000!important}
|
||||
.w3-grey,.w3-hover-grey:hover,.w3-gray,.w3-hover-gray:hover{color:#000!important;background-color:#9e9e9e!important}
|
||||
.w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
|
||||
.w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,.w3-hover-dark-gray:hover{color:#fff!important;background-color:#616161!important}
|
||||
.w3-asphalt,.w3-hover-asphalt:hover{color:#fff!important;background-color:#343a40!important}
|
||||
.w3-crimson,.w3-hover-crimson:hover{color:#fff!important;background-color:#a20025!important}
|
||||
.w3-cobalt,w3-hover-cobalt:hover{color:#fff!important;background-color:#0050ef!important}
|
||||
.w3-emerald,.w3-hover-emerald:hover{color:#fff!important;background-color:#008a00!important}
|
||||
.w3-olive,.w3-hover-olive:hover{color:#fff!important;background-color:#6d8764!important}
|
||||
.w3-paper,.w3-hover-paper:hover{color:#000!important;background-color:#f8f9fa!important}
|
||||
.w3-sienna,.w3-hover-sienna:hover{color:#fff!important;background-color:#a0522d!important}
|
||||
.w3-taupe,.w3-hover-taupe:hover{color:#fff!important;background-color:#87794e!important}
|
||||
.w3-danger{color:#fff!important;background-color:#dd0000!important}
|
||||
.w3-note{color:#000!important;background-color:#fff599!important}
|
||||
.w3-info{color:#fff!important;background-color:#0a6fc2!important}
|
||||
.w3-warning{color:#000!important;background-color:#ffb305!important}
|
||||
.w3-success{color:#fff!important;background-color:#008a00!important}
|
||||
.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffdddd!important}
|
||||
.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#ddffdd!important}
|
||||
.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffcc!important}
|
||||
.w3-pale-blue,.w3-hover-pale-blue:hover{color:#000!important;background-color:#ddffff!important}
|
||||
.w3-text-amber,.w3-hover-text-amber:hover{color:#ffc107!important}
|
||||
.w3-text-aqua,.w3-hover-text-aqua:hover{color:#00ffff!important}
|
||||
.w3-text-blue,.w3-hover-text-blue:hover{color:#2196F3!important}
|
||||
.w3-text-light-blue,.w3-hover-text-light-blue:hover{color:#87CEEB!important}
|
||||
.w3-text-brown,.w3-hover-text-brown:hover{color:#795548!important}
|
||||
.w3-text-cyan,.w3-hover-text-cyan:hover{color:#00bcd4!important}
|
||||
.w3-text-blue-grey,.w3-hover-text-blue-grey:hover,.w3-text-blue-gray,.w3-hover-text-blue-gray:hover{color:#607d8b!important}
|
||||
.w3-text-green,.w3-hover-text-green:hover{color:#4CAF50!important}
|
||||
.w3-text-light-green,.w3-hover-text-light-green:hover{color:#8bc34a!important}
|
||||
.w3-text-indigo,.w3-hover-text-indigo:hover{color:#3f51b5!important}
|
||||
.w3-text-khaki,.w3-hover-text-khaki:hover{color:#b4aa50!important}
|
||||
.w3-text-lime,.w3-hover-text-lime:hover{color:#cddc39!important}
|
||||
.w3-text-orange,.w3-hover-text-orange:hover{color:#ff9800!important}
|
||||
.w3-text-deep-orange,.w3-hover-text-deep-orange:hover{color:#ff5722!important}
|
||||
.w3-text-pink,.w3-hover-text-pink:hover{color:#e91e63!important}
|
||||
.w3-text-purple,.w3-hover-text-purple:hover{color:#9c27b0!important}
|
||||
.w3-text-deep-purple,.w3-hover-text-deep-purple:hover{color:#673ab7!important}
|
||||
.w3-text-red,.w3-hover-text-red:hover{color:#f44336!important}
|
||||
.w3-text-sand,.w3-hover-text-sand:hover{color:#fdf5e6!important}
|
||||
.w3-text-teal,.w3-hover-text-teal:hover{color:#009688!important}
|
||||
.w3-text-yellow,.w3-hover-text-yellow:hover{color:#d2be0e!important}
|
||||
.w3-text-white,.w3-hover-text-white:hover{color:#fff!important}
|
||||
.w3-text-black,.w3-hover-text-black:hover{color:#000!important}
|
||||
.w3-text-grey,.w3-hover-text-grey:hover,.w3-text-gray,.w3-hover-text-gray:hover{color:#757575!important}
|
||||
.w3-text-light-grey,.w3-hover-text-light-grey:hover,.w3-text-light-gray,.w3-hover-text-light-gray:hover{color:#f1f1f1!important}
|
||||
.w3-text-dark-grey,.w3-hover-text-dark-grey:hover,.w3-text-dark-gray,.w3-hover-text-dark-gray:hover{color:#3a3a3a!important}
|
||||
.w3-border-amber,.w3-hover-border-amber:hover{border-color:#ffc107!important}
|
||||
.w3-border-aqua,.w3-hover-border-aqua:hover{border-color:#00ffff!important}
|
||||
.w3-border-blue,.w3-hover-border-blue:hover{border-color:#2196F3!important}
|
||||
.w3-border-light-blue,.w3-hover-border-light-blue:hover{border-color:#87CEEB!important}
|
||||
.w3-border-brown,.w3-hover-border-brown:hover{border-color:#795548!important}
|
||||
.w3-border-cyan,.w3-hover-border-cyan:hover{border-color:#00bcd4!important}
|
||||
.w3-border-blue-grey,.w3-hover-border-blue-grey:hover,.w3-border-blue-gray,.w3-hover-border-blue-gray:hover{border-color:#607d8b!important}
|
||||
.w3-border-green,.w3-hover-border-green:hover{border-color:#4CAF50!important}
|
||||
.w3-border-light-green,.w3-hover-border-light-green:hover{border-color:#8bc34a!important}
|
||||
.w3-border-indigo,.w3-hover-border-indigo:hover{border-color:#3f51b5!important}
|
||||
.w3-border-khaki,.w3-hover-border-khaki:hover{border-color:#f0e68c!important}
|
||||
.w3-border-lime,.w3-hover-border-lime:hover{border-color:#cddc39!important}
|
||||
.w3-border-orange,.w3-hover-border-orange:hover{border-color:#ff9800!important}
|
||||
.w3-border-deep-orange,.w3-hover-border-deep-orange:hover{border-color:#ff5722!important}
|
||||
.w3-border-pink,.w3-hover-border-pink:hover{border-color:#e91e63!important}
|
||||
.w3-border-purple,.w3-hover-border-purple:hover{border-color:#9c27b0!important}
|
||||
.w3-border-deep-purple,.w3-hover-border-deep-purple:hover{border-color:#673ab7!important}
|
||||
.w3-border-red,.w3-hover-border-red:hover{border-color:#f44336!important}
|
||||
.w3-border-sand,.w3-hover-border-sand:hover{border-color:#fdf5e6!important}
|
||||
.w3-border-teal,.w3-hover-border-teal:hover{border-color:#009688!important}
|
||||
.w3-border-yellow,.w3-hover-border-yellow:hover{border-color:#ffeb3b!important}
|
||||
.w3-border-white,.w3-hover-border-white:hover{border-color:#fff!important}
|
||||
.w3-border-black,.w3-hover-border-black:hover{border-color:#000!important}
|
||||
.w3-border-grey,.w3-hover-border-grey:hover,.w3-border-gray,.w3-hover-border-gray:hover{border-color:#9e9e9e!important}
|
||||
.w3-border-light-grey,.w3-hover-border-light-grey:hover,.w3-border-light-gray,.w3-hover-border-light-gray:hover{border-color:#f1f1f1!important}
|
||||
.w3-border-dark-grey,.w3-hover-border-dark-grey:hover,.w3-border-dark-gray,.w3-hover-border-dark-gray:hover{border-color:#616161!important}
|
||||
.w3-border-pale-red,.w3-hover-border-pale-red:hover{border-color:#ffe7e7!important}.w3-border-pale-green,.w3-hover-border-pale-green:hover{border-color:#e7ffe7!important}
|
||||
.w3-border-pale-yellow,.w3-hover-border-pale-yellow:hover{border-color:#ffffcc!important}.w3-border-pale-blue,.w3-hover-border-pale-blue:hover{border-color:#e7ffff!important}
|
||||
10
app/src/web/static/font-awesome/css/all.min.css
vendored
|
Before Width: | Height: | Size: 730 KiB |
@@ -1,801 +0,0 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
|
||||
<metadata>
|
||||
Created by FontForge 20201107 at Wed Aug 4 12:25:29 2021
|
||||
By Robert Madole
|
||||
Copyright (c) Font Awesome
|
||||
</metadata>
|
||||
<!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><defs>
|
||||
<font id="FontAwesome5Free-Regular" horiz-adv-x="512" >
|
||||
<font-face
|
||||
font-family="Font Awesome 5 Free Regular"
|
||||
font-weight="400"
|
||||
font-stretch="normal"
|
||||
units-per-em="512"
|
||||
panose-1="2 0 5 3 0 0 0 0 0 0"
|
||||
ascent="448"
|
||||
descent="-64"
|
||||
bbox="-0.0663408 -64.0662 640.004 448.1"
|
||||
underline-thickness="25"
|
||||
underline-position="-50"
|
||||
unicode-range="U+0020-F5C8"
|
||||
/>
|
||||
<missing-glyph />
|
||||
<glyph glyph-name="heart" unicode=""
|
||||
d="M458.4 383.7c75.2998 -63.4004 64.0996 -166.601 10.5996 -221.3l-175.4 -178.7c-10 -10.2002 -23.2998 -15.7998 -37.5996 -15.7998c-14.2002 0 -27.5996 5.69922 -37.5996 15.8994l-175.4 178.7c-53.5996 54.7002 -64.5996 157.9 10.5996 221.2
|
||||
c57.8008 48.7002 147.101 41.2998 202.4 -15c55.2998 56.2998 144.6 63.5996 202.4 15zM434.8 196.2c36.2002 36.8994 43.7998 107.7 -7.2998 150.8c-38.7002 32.5996 -98.7002 27.9004 -136.5 -10.5996l-35 -35.7002l-35 35.7002
|
||||
c-37.5996 38.2998 -97.5996 43.1992 -136.5 10.5c-51.2002 -43.1006 -43.7998 -113.5 -7.2998 -150.7l175.399 -178.7c2.40039 -2.40039 4.40039 -2.40039 6.80078 0z" />
|
||||
<glyph glyph-name="star" unicode="" horiz-adv-x="576"
|
||||
d="M528.1 276.5c26.2002 -3.7998 36.7002 -36.0996 17.7002 -54.5996l-105.7 -103l25 -145.5c4.5 -26.3008 -23.1992 -45.9004 -46.3994 -33.7002l-130.7 68.7002l-130.7 -68.7002c-23.2002 -12.2998 -50.8994 7.39941 -46.3994 33.7002l25 145.5l-105.7 103
|
||||
c-19 18.5 -8.5 50.7998 17.7002 54.5996l146.1 21.2998l65.2998 132.4c11.7998 23.8994 45.7002 23.5996 57.4004 0l65.2998 -132.4zM388.6 135.7l100.601 98l-139 20.2002l-62.2002 126l-62.2002 -126l-139 -20.2002l100.601 -98l-23.7002 -138.4l124.3 65.2998
|
||||
l124.3 -65.2998z" />
|
||||
<glyph glyph-name="user" unicode="" horiz-adv-x="448"
|
||||
d="M313.6 144c74.2002 0 134.4 -60.2002 134.4 -134.4v-25.5996c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v25.5996c0 74.2002 60.2002 134.4 134.4 134.4c28.7998 0 42.5 -16 89.5996 -16s60.9004 16 89.5996 16zM400 -16v25.5996
|
||||
c0 47.6006 -38.7998 86.4004 -86.4004 86.4004c-14.6992 0 -37.8994 -16 -89.5996 -16c-51.2998 0 -75 16 -89.5996 16c-47.6006 0 -86.4004 -38.7998 -86.4004 -86.4004v-25.5996h352zM224 160c-79.5 0 -144 64.5 -144 144s64.5 144 144 144s144 -64.5 144 -144
|
||||
s-64.5 -144 -144 -144zM224 400c-52.9004 0 -96 -43.0996 -96 -96s43.0996 -96 96 -96s96 43.0996 96 96s-43.0996 96 -96 96z" />
|
||||
<glyph glyph-name="clock" unicode=""
|
||||
d="M256 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM256 -8c110.5 0 200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200s89.5 -200 200 -200zM317.8 96.4004l-84.8994 61.6992
|
||||
c-3.10059 2.30078 -4.90039 5.90039 -4.90039 9.7002v164.2c0 6.59961 5.40039 12 12 12h32c6.59961 0 12 -5.40039 12 -12v-141.7l66.7998 -48.5996c5.40039 -3.90039 6.5 -11.4004 2.60059 -16.7998l-18.8008 -25.9004c-3.89941 -5.2998 -11.3994 -6.5 -16.7998 -2.59961z
|
||||
" />
|
||||
<glyph glyph-name="list-alt" unicode=""
|
||||
d="M464 416c26.5098 0 48 -21.4902 48 -48v-352c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v352c0 26.5098 21.4902 48 48 48h416zM458 16c3.31152 0 6 2.68848 6 6v340c0 3.31152 -2.68848 6 -6 6h-404c-3.31152 0 -6 -2.68848 -6 -6v-340
|
||||
c0 -3.31152 2.68848 -6 6 -6h404zM416 108v-24c0 -6.62695 -5.37305 -12 -12 -12h-200c-6.62695 0 -12 5.37305 -12 12v24c0 6.62695 5.37305 12 12 12h200c6.62695 0 12 -5.37305 12 -12zM416 204v-24c0 -6.62695 -5.37305 -12 -12 -12h-200c-6.62695 0 -12 5.37305 -12 12
|
||||
v24c0 6.62695 5.37305 12 12 12h200c6.62695 0 12 -5.37305 12 -12zM416 300v-24c0 -6.62695 -5.37305 -12 -12 -12h-200c-6.62695 0 -12 5.37305 -12 12v24c0 6.62695 5.37305 12 12 12h200c6.62695 0 12 -5.37305 12 -12zM164 288c0 -19.8818 -16.1182 -36 -36 -36
|
||||
s-36 16.1182 -36 36s16.1182 36 36 36s36 -16.1182 36 -36zM164 192c0 -19.8818 -16.1182 -36 -36 -36s-36 16.1182 -36 36s16.1182 36 36 36s36 -16.1182 36 -36zM164 96c0 -19.8818 -16.1182 -36 -36 -36s-36 16.1182 -36 36s16.1182 36 36 36s36 -16.1182 36 -36z" />
|
||||
<glyph glyph-name="flag" unicode=""
|
||||
d="M336.174 368c35.4668 0 73.0195 12.6914 108.922 28.1797c31.6406 13.6514 66.9043 -9.65723 66.9043 -44.1162v-239.919c0 -16.1953 -8.1543 -31.3057 -21.7129 -40.1631c-26.5762 -17.3643 -70.0693 -39.9814 -128.548 -39.9814c-68.6084 0 -112.781 32 -161.913 32
|
||||
c-56.5674 0 -89.957 -11.2803 -127.826 -28.5566v-83.4434c0 -8.83691 -7.16309 -16 -16 -16h-16c-8.83691 0 -16 7.16309 -16 16v406.438c-14.3428 8.2998 -24 23.7979 -24 41.5615c0 27.5693 23.2422 49.71 51.2012 47.8965
|
||||
c22.9658 -1.49023 41.8662 -19.4717 44.4805 -42.3379c0.213867 -1.83398 0.308594 -3.65918 0.308594 -5.5498c0 -5.30273 -0.860352 -10.4053 -2.4502 -15.1768c22.418 8.68555 49.4199 15.168 80.7207 15.168c68.6084 0 112.781 -32 161.913 -32zM464 112v240
|
||||
c-31.5059 -14.6338 -84.5547 -32 -127.826 -32c-59.9111 0 -101.968 32 -161.913 32c-41.4365 0 -80.4766 -16.5879 -102.261 -32v-232c31.4473 14.5967 84.4648 24 127.826 24c59.9111 0 101.968 -32 161.913 -32c41.4365 0 80.4775 16.5879 102.261 32z" />
|
||||
<glyph glyph-name="bookmark" unicode="" horiz-adv-x="384"
|
||||
d="M336 448c26.5098 0 48 -21.4902 48 -48v-464l-192 112l-192 -112v464c0 26.5098 21.4902 48 48 48h288zM336 19.5703v374.434c0 3.31348 -2.68555 5.99609 -6 5.99609h-276c-3.31152 0 -6 -2.68848 -6 -6v-374.43l144 84z" />
|
||||
<glyph glyph-name="image" unicode=""
|
||||
d="M464 384c26.5098 0 48 -21.4902 48 -48v-288c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v288c0 26.5098 21.4902 48 48 48h416zM458 48c3.31152 0 6 2.68848 6 6v276c0 3.31152 -2.68848 6 -6 6h-404c-3.31152 0 -6 -2.68848 -6 -6v-276
|
||||
c0 -3.31152 2.68848 -6 6 -6h404zM128 296c22.0908 0 40 -17.9092 40 -40s-17.9092 -40 -40 -40s-40 17.9092 -40 40s17.9092 40 40 40zM96 96v48l39.5137 39.5146c4.6875 4.68652 12.2852 4.68652 16.9717 0l39.5146 -39.5146l119.514 119.515
|
||||
c4.6875 4.68652 12.2852 4.68652 16.9717 0l87.5146 -87.5146v-80h-320z" />
|
||||
<glyph glyph-name="edit" unicode="" horiz-adv-x="576"
|
||||
d="M402.3 103.1l32 32c5 5 13.7002 1.5 13.7002 -5.69922v-145.4c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h273.5c7.09961 0 10.7002 -8.59961 5.7002 -13.7002l-32 -32c-1.5 -1.5 -3.5 -2.2998 -5.7002 -2.2998h-241.5v-352h352
|
||||
v113.5c0 2.09961 0.799805 4.09961 2.2998 5.59961zM558.9 304.9l-262.601 -262.601l-90.3994 -10c-26.2002 -2.89941 -48.5 19.2002 -45.6006 45.6006l10 90.3994l262.601 262.601c22.8994 22.8994 59.8994 22.8994 82.6992 0l43.2002 -43.2002
|
||||
c22.9004 -22.9004 22.9004 -60 0.100586 -82.7998zM460.1 274l-58.0996 58.0996l-185.8 -185.899l-7.2998 -65.2998l65.2998 7.2998zM524.9 353.7l-43.2002 43.2002c-4.10059 4.09961 -10.7998 4.09961 -14.7998 0l-30.9004 -30.9004l58.0996 -58.0996l30.9004 30.8994
|
||||
c4 4.2002 4 10.7998 -0.0996094 14.9004z" />
|
||||
<glyph glyph-name="times-circle" unicode=""
|
||||
d="M256 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM256 -8c110.5 0 200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200s89.5 -200 200 -200zM357.8 254.2l-62.2002 -62.2002l62.2002 -62.2002
|
||||
c4.7002 -4.7002 4.7002 -12.2998 0 -17l-22.5996 -22.5996c-4.7002 -4.7002 -12.2998 -4.7002 -17 0l-62.2002 62.2002l-62.2002 -62.2002c-4.7002 -4.7002 -12.2998 -4.7002 -17 0l-22.5996 22.5996c-4.7002 4.7002 -4.7002 12.2998 0 17l62.2002 62.2002l-62.2002 62.2002
|
||||
c-4.7002 4.7002 -4.7002 12.2998 0 17l22.5996 22.5996c4.7002 4.7002 12.2998 4.7002 17 0l62.2002 -62.2002l62.2002 62.2002c4.7002 4.7002 12.2998 4.7002 17 0l22.5996 -22.5996c4.7002 -4.7002 4.7002 -12.2998 0 -17z" />
|
||||
<glyph glyph-name="check-circle" unicode=""
|
||||
d="M256 440c136.967 0 248 -111.033 248 -248s-111.033 -248 -248 -248s-248 111.033 -248 248s111.033 248 248 248zM256 392c-110.549 0 -200 -89.4678 -200 -200c0 -110.549 89.4678 -200 200 -200c110.549 0 200 89.4678 200 200c0 110.549 -89.4678 200 -200 200z
|
||||
M396.204 261.733c4.66699 -4.70508 4.63672 -12.3037 -0.0673828 -16.9717l-172.589 -171.204c-4.70508 -4.66797 -12.3027 -4.63672 -16.9697 0.0683594l-90.7812 91.5156c-4.66797 4.70605 -4.63672 12.3047 0.0683594 16.9717l22.7188 22.5361
|
||||
c4.70508 4.66699 12.3027 4.63574 16.9697 -0.0693359l59.792 -60.2773l141.353 140.216c4.70508 4.66797 12.3027 4.6377 16.9697 -0.0673828z" />
|
||||
<glyph glyph-name="question-circle" unicode=""
|
||||
d="M256 440c136.957 0 248 -111.083 248 -248c0 -136.997 -111.043 -248 -248 -248s-248 111.003 -248 248c0 136.917 111.043 248 248 248zM256 -8c110.569 0 200 89.4697 200 200c0 110.529 -89.5088 200 -200 200c-110.528 0 -200 -89.5049 -200 -200
|
||||
c0 -110.569 89.4678 -200 200 -200zM363.244 247.2c0 -67.0518 -72.4209 -68.084 -72.4209 -92.8633v-6.33691c0 -6.62695 -5.37305 -12 -12 -12h-45.6475c-6.62695 0 -12 5.37305 -12 12v8.65918c0 35.7451 27.1006 50.0342 47.5791 61.5156
|
||||
c17.5615 9.84473 28.3242 16.541 28.3242 29.5791c0 17.2461 -21.999 28.6934 -39.7842 28.6934c-23.1885 0 -33.8936 -10.9775 -48.9424 -29.9697c-4.05664 -5.11914 -11.46 -6.07031 -16.666 -2.12402l-27.8232 21.0986
|
||||
c-5.10742 3.87207 -6.25098 11.0654 -2.64453 16.3633c23.627 34.6934 53.7217 54.1846 100.575 54.1846c49.0713 0 101.45 -38.3037 101.45 -88.7998zM298 80c0 -23.1592 -18.8408 -42 -42 -42s-42 18.8408 -42 42s18.8408 42 42 42s42 -18.8408 42 -42z" />
|
||||
<glyph glyph-name="eye" unicode="" horiz-adv-x="576"
|
||||
d="M288 304c0.114258 0 0.240234 -0.0175781 0.354492 -0.0175781c61.6543 0 111.71 -50.0557 111.71 -111.71s-50.0557 -111.71 -111.71 -111.71s-111.71 50.0557 -111.71 111.71c0 10.7422 1.51953 21.1328 4.35547 30.9678
|
||||
c7.95898 -4.52637 17.2129 -7.17188 27 -7.24023c30.9072 0 56 25.0928 56 56c-0.0683594 9.78711 -2.71387 19.041 -7.24023 27c9.88379 3.07617 20.3896 4.83008 31.2402 5zM572.52 206.6c2.21387 -4.37793 3.46094 -9.38965 3.46094 -14.626
|
||||
c0 -5.2373 -1.24707 -10.1855 -3.46094 -14.5635c-54.1992 -105.771 -161.59 -177.41 -284.52 -177.41s-230.29 71.5898 -284.52 177.4c-2.21387 4.37793 -3.46094 9.38965 -3.46094 14.626c0 5.2373 1.24707 10.1855 3.46094 14.5635
|
||||
c54.1992 105.771 161.59 177.41 284.52 177.41s230.29 -71.5898 284.52 -177.4zM288 48c98.6602 0 189.1 55 237.93 144c-48.8398 89 -139.27 144 -237.93 144s-189.09 -55 -237.93 -144c48.8398 -89 139.279 -144 237.93 -144z" />
|
||||
<glyph glyph-name="eye-slash" unicode="" horiz-adv-x="640"
|
||||
d="M634 -23c3.66895 -2.93262 6.00391 -7.45117 6.00391 -12.5088c0 -3.7832 -1.31543 -7.26074 -3.51367 -10.001l-10 -12.4902c-2.93359 -3.66309 -7.44824 -5.99414 -12.502 -5.99414c-3.77637 0 -7.25 1.31152 -9.98828 3.50391l-598 467.49
|
||||
c-3.66895 2.93262 -6.00391 7.45117 -6.00391 12.5088c0 3.7832 1.31543 7.26074 3.51367 10.001l10 12.4902c2.93359 3.66309 7.44824 5.99414 12.502 5.99414c3.77637 0 7.25 -1.31152 9.98828 -3.50391zM296.79 301.53c7.51172 1.60254 15.2266 2.45508 23.21 2.46973
|
||||
c60.4805 0 109.36 -47.9102 111.58 -107.85zM343.21 82.46c-7.51367 -1.59375 -15.2285 -2.44336 -23.21 -2.45996c-60.4697 0 -109.35 47.9102 -111.58 107.84zM320 336c-19.8799 0 -39.2803 -2.7998 -58.2197 -7.09961l-46.4102 36.29
|
||||
c32.9199 11.8096 67.9297 18.8096 104.63 18.8096c122.93 0 230.29 -71.5898 284.57 -177.4c2.21289 -4.37793 3.45996 -9.38965 3.45996 -14.626c0 -5.2373 -1.24707 -10.1855 -3.45996 -14.5635c-14.1924 -27.5625 -31.9229 -52.6689 -52.9004 -75.1104l-37.7402 29.5
|
||||
c17.2305 18.0527 31.9385 38.1318 44 60.2002c-48.8398 89 -139.279 144 -237.93 144zM320 48c19.8896 0 39.2803 2.7998 58.2197 7.08984l46.4102 -36.2803c-32.9199 -11.7598 -67.9297 -18.8096 -104.63 -18.8096c-122.92 0 -230.28 71.5898 -284.51 177.4
|
||||
c-2.21387 4.37793 -3.46094 9.38965 -3.46094 14.626c0 5.2373 1.24707 10.1855 3.46094 14.5635c14.1885 27.5586 31.916 52.6621 52.8896 75.1006l37.7402 -29.5c-17.249 -18.0469 -31.9727 -38.1221 -44.0498 -60.1904c48.8496 -89 139.279 -144 237.93 -144z" />
|
||||
<glyph glyph-name="calendar-alt" unicode="" horiz-adv-x="448"
|
||||
d="M148 160h-40c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12zM256 172c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40
|
||||
c6.59961 0 12 -5.40039 12 -12v-40zM352 172c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40zM256 76c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12v40
|
||||
c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40zM160 76c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40zM352 76c0 -6.59961 -5.40039 -12 -12 -12h-40
|
||||
c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40zM448 336v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h48v52c0 6.59961 5.40039 12 12 12h40
|
||||
c6.59961 0 12 -5.40039 12 -12v-52h128v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h48c26.5 0 48 -21.5 48 -48zM400 -10v298h-352v-298c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
||||
<glyph glyph-name="comment" unicode=""
|
||||
d="M256 416c141.4 0 256 -93.0996 256 -208s-114.6 -208 -256 -208c-32.7998 0 -64 5.2002 -92.9004 14.2998c-29.0996 -20.5996 -77.5996 -46.2998 -139.1 -46.2998c-9.59961 0 -18.2998 5.7002 -22.0996 14.5c-3.80078 8.7998 -2 19 4.59961 26
|
||||
c0.5 0.400391 31.5 33.7998 46.4004 73.2002c-33 35.0996 -52.9004 78.7002 -52.9004 126.3c0 114.9 114.6 208 256 208zM256 48c114.7 0 208 71.7998 208 160s-93.2998 160 -208 160s-208 -71.7998 -208 -160c0 -42.2002 21.7002 -74.0996 39.7998 -93.4004
|
||||
l20.6006 -21.7998l-10.6006 -28.0996c-5.5 -14.5 -12.5996 -28.1006 -19.8994 -40.2002c23.5996 7.59961 43.1992 18.9004 57.5 29l19.5 13.7998l22.6992 -7.2002c25.3008 -8 51.7002 -12.0996 78.4004 -12.0996z" />
|
||||
<glyph glyph-name="folder" unicode=""
|
||||
d="M464 320c26.5098 0 48 -21.4902 48 -48v-224c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v288c0 26.5098 21.4902 48 48 48h146.74c8.49023 0 16.6299 -3.37012 22.6299 -9.37012l54.6299 -54.6299h192zM464 48v224h-198.62
|
||||
c-8.49023 0 -16.6299 3.37012 -22.6299 9.37012l-54.6299 54.6299h-140.12v-288h416z" />
|
||||
<glyph glyph-name="folder-open" unicode="" horiz-adv-x="576"
|
||||
d="M527.9 224c37.6992 0 60.6992 -41.5 40.6992 -73.4004l-79.8994 -128c-8.7998 -14.0996 -24.2002 -22.5996 -40.7002 -22.5996h-400c-26.5 0 -48 21.5 -48 48v288c0 26.5 21.5 48 48 48h160l64 -64h160c26.5 0 48 -21.5 48 -48v-48h47.9004zM48 330v-233.4l62.9004 104.2
|
||||
c8.69922 14.4004 24.2998 23.2002 41.0996 23.2002h280v42c0 3.2998 -2.7002 6 -6 6h-173.9l-64 64h-134.1c-3.2998 0 -6 -2.7002 -6 -6zM448 48l80 128h-378.8l-77.2002 -128h376z" />
|
||||
<glyph glyph-name="chart-bar" unicode=""
|
||||
d="M396.8 96c-6.39941 0 -12.7998 6.40039 -12.7998 12.7998v230.4c0 6.39941 6.40039 12.7998 12.7998 12.7998h22.4004c6.39941 0 12.7998 -6.40039 12.7998 -12.7998v-230.4c0 -6.39941 -6.40039 -12.7998 -12.7998 -12.7998h-22.4004zM204.8 96
|
||||
c-6.39941 0 -12.7998 6.40039 -12.7998 12.7998v198.4c0 6.39941 6.40039 12.7998 12.7998 12.7998h22.4004c6.39941 0 12.7998 -6.40039 12.7998 -12.7998v-198.4c0 -6.39941 -6.40039 -12.7998 -12.7998 -12.7998h-22.4004zM300.8 96
|
||||
c-6.39941 0 -12.7998 6.40039 -12.7998 12.7998v134.4c0 6.39941 6.40039 12.7998 12.7998 12.7998h22.4004c6.39941 0 12.7998 -6.40039 12.7998 -12.7998v-134.4c0 -6.39941 -6.40039 -12.7998 -12.7998 -12.7998h-22.4004zM496 48c8.83984 0 16 -7.16016 16 -16v-16
|
||||
c0 -8.83984 -7.16016 -16 -16 -16h-464c-17.6699 0 -32 14.3301 -32 32v336c0 8.83984 7.16016 16 16 16h16c8.83984 0 16 -7.16016 16 -16v-320h448zM108.8 96c-6.39941 0 -12.7998 6.40039 -12.7998 12.7998v70.4004c0 6.39941 6.40039 12.7998 12.7998 12.7998h22.4004
|
||||
c6.39941 0 12.7998 -6.40039 12.7998 -12.7998v-70.4004c0 -6.39941 -6.40039 -12.7998 -12.7998 -12.7998h-22.4004z" />
|
||||
<glyph glyph-name="comments" unicode="" horiz-adv-x="576"
|
||||
d="M532 61.7998c15.2998 -30.7002 37.4004 -54.5 37.7998 -54.7998c6.2998 -6.7002 8 -16.5 4.40039 -25c-3.7002 -8.5 -12 -14 -21.2002 -14c-53.5996 0 -96.7002 20.2998 -125.2 38.7998c-19 -4.39941 -39 -6.7998 -59.7998 -6.7998
|
||||
c-86.2002 0 -159.9 40.4004 -191.3 97.7998c-9.7002 1.2002 -19.2002 2.7998 -28.4004 4.90039c-28.5 -18.6006 -71.7002 -38.7998 -125.2 -38.7998c-9.19922 0 -17.5996 5.5 -21.1992 14c-3.7002 8.5 -1.90039 18.2998 4.39941 25
|
||||
c0.400391 0.399414 22.4004 24.1992 37.7002 54.8994c-27.5 27.2002 -44 61.2002 -44 98.2002c0 88.4004 93.0996 160 208 160c86.2998 0 160.3 -40.5 191.8 -98.0996c99.7002 -11.8008 176.2 -77.9004 176.2 -157.9c0 -37.0996 -16.5 -71.0996 -44 -98.2002zM139.2 154.1
|
||||
l19.7998 -4.5c16 -3.69922 32.5 -5.59961 49 -5.59961c86.7002 0 160 51.2998 160 112s-73.2998 112 -160 112s-160 -51.2998 -160 -112c0 -28.7002 16.2002 -50.5996 29.7002 -64l24.7998 -24.5l-15.5 -31.0996c-2.59961 -5.10059 -5.2998 -10.1006 -8 -14.8008
|
||||
c14.5996 5.10059 29 12.3008 43.0996 21.4004zM498.3 96c13.5 13.4004 29.7002 35.2998 29.7002 64c0 49.2002 -48.2998 91.5 -112.7 106c0.299805 -3.2998 0.700195 -6.59961 0.700195 -10c0 -80.9004 -78 -147.5 -179.3 -158.3
|
||||
c29.0996 -29.6006 77.2998 -49.7002 131.3 -49.7002c16.5 0 33 1.90039 49 5.59961l19.9004 4.60059l17.0996 -11.1006c14.0996 -9.09961 28.5 -16.2998 43.0996 -21.3994c-2.69922 4.7002 -5.39941 9.7002 -8 14.7998l-15.5 31.0996z" />
|
||||
<glyph glyph-name="star-half" unicode="" horiz-adv-x="576"
|
||||
d="M288 62.7002v-54.2998l-130.7 -68.6006c-23.3994 -12.2998 -50.8994 7.60059 -46.3994 33.7002l25 145.5l-105.7 103c-19 18.5 -8.5 50.7998 17.7002 54.5996l146.1 21.2002l65.2998 132.4c5.90039 11.8994 17.2998 17.7998 28.7002 17.7998v-68.0996l-62.2002 -126
|
||||
l-139 -20.2002l100.601 -98l-23.7002 -138.4z" />
|
||||
<glyph glyph-name="lemon" unicode=""
|
||||
d="M484.112 420.111c28.1221 -28.123 35.9434 -68.0039 19.0215 -97.0547c-23.0576 -39.584 50.1436 -163.384 -82.3311 -295.86c-132.301 -132.298 -256.435 -59.3594 -295.857 -82.3291c-29.0459 -16.917 -68.9219 -9.11426 -97.0576 19.0205
|
||||
c-28.1221 28.1221 -35.9434 68.0029 -19.0215 97.0547c23.0566 39.5859 -50.1436 163.386 82.3301 295.86c132.308 132.309 256.407 59.3496 295.862 82.332c29.0498 16.9219 68.9307 9.09863 97.0537 -19.0234zM461.707 347.217
|
||||
c13.5166 23.2031 -27.7578 63.7314 -50.4883 50.4912c-66.6025 -38.7939 -165.646 45.5898 -286.081 -74.8457c-120.444 -120.445 -36.0449 -219.472 -74.8447 -286.08c-13.542 -23.2471 27.8145 -63.6953 50.4932 -50.4883
|
||||
c66.6006 38.7949 165.636 -45.5996 286.076 74.8428c120.444 120.445 36.0449 219.472 74.8447 286.08zM291.846 338.481c1.37012 -10.96 -6.40332 -20.957 -17.3643 -22.3271c-54.8467 -6.85547 -135.779 -87.7871 -142.636 -142.636
|
||||
c-1.37305 -10.9883 -11.3984 -18.7334 -22.3262 -17.3643c-10.9609 1.37012 -18.7344 11.3652 -17.3643 22.3262c9.16211 73.2852 104.167 168.215 177.364 177.364c10.9531 1.36816 20.9561 -6.40234 22.3262 -17.3633z" />
|
||||
<glyph glyph-name="credit-card" unicode="" horiz-adv-x="576"
|
||||
d="M527.9 416c26.5996 0 48.0996 -21.5 48.0996 -48v-352c0 -26.5 -21.5 -48 -48.0996 -48h-479.801c-26.5996 0 -48.0996 21.5 -48.0996 48v352c0 26.5 21.5 48 48.0996 48h479.801zM54.0996 368c-3.2998 0 -6 -2.7002 -6 -6v-42h479.801v42c0 3.2998 -2.7002 6 -6 6
|
||||
h-467.801zM521.9 16c3.2998 0 6 2.7002 6 6v170h-479.801v-170c0 -3.2998 2.7002 -6 6 -6h467.801zM192 116v-40c0 -6.59961 -5.40039 -12 -12 -12h-72c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h72c6.59961 0 12 -5.40039 12 -12zM384 116v-40
|
||||
c0 -6.59961 -5.40039 -12 -12 -12h-136c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h136c6.59961 0 12 -5.40039 12 -12z" />
|
||||
<glyph glyph-name="hdd" unicode="" horiz-adv-x="576"
|
||||
d="M567.403 212.358c5.59668 -8.04688 8.59668 -17.6113 8.59668 -27.4121v-136.946c0 -26.5098 -21.4902 -48 -48 -48h-480c-26.5098 0 -48 21.4902 -48 48v136.946c0 10.167 3.19531 19.6465 8.59668 27.4121l105.08 151.053
|
||||
c8.67383 12.4678 23.0791 20.5889 39.4043 20.5889h269.838c16.3252 0 30.7305 -8.12109 39.4043 -20.5889zM153.081 336l-77.9131 -112h425.664l-77.9131 112h-269.838zM528 48v128h-480v-128h480zM496 112c0 -17.6729 -14.3271 -32 -32 -32s-32 14.3271 -32 32
|
||||
s14.3271 32 32 32s32 -14.3271 32 -32zM400 112c0 -17.6729 -14.3271 -32 -32 -32s-32 14.3271 -32 32s14.3271 32 32 32s32 -14.3271 32 -32z" />
|
||||
<glyph glyph-name="hand-point-right" unicode=""
|
||||
d="M428.8 310.4c45.0996 0 83.2002 -38.1016 83.2002 -83.2002c0 -45.6162 -37.7646 -83.2002 -83.2002 -83.2002h-35.6475c-1.71387 -7.70605 -4.43555 -15.2051 -7.92969 -22.0645c2.50586 -22.0059 -3.50293 -44.9775 -15.9844 -62.791
|
||||
c-1.14062 -52.4863 -37.3984 -91.1445 -99.9404 -91.1445h-21.2988c-60.0635 0 -98.5117 40 -127.2 40h-2.67871c-5.74707 -4.95215 -13.5361 -8 -22.1201 -8h-64c-17.6729 0 -32 12.8936 -32 28.7998v230.4c0 15.9062 14.3271 28.7998 32 28.7998h64.001
|
||||
c8.58398 0 16.373 -3.04785 22.1201 -8h2.67871c6.96387 0 14.8623 6.19336 30.1816 23.6689l0.128906 0.148438l0.130859 0.145508c8.85645 9.93652 18.1162 20.8398 25.8506 33.2529c18.7051 30.2471 30.3936 78.7842 75.707 78.7842c56.9277 0 92 -35.2861 92 -83.2002
|
||||
c0 -0.0283203 0 0.0361328 0 0.0078125c0 -7.66602 -0.748047 -15.1582 -2.17578 -22.4072h86.1768zM428.8 192c18.9756 0 35.2002 16.2246 35.2002 35.2002c0 18.7002 -16.7754 35.2002 -35.2002 35.2002h-158.399c0 17.3242 26.3994 35.1992 26.3994 70.3994
|
||||
c0 26.4004 -20.625 35.2002 -44 35.2002c-8.79395 0 -20.4443 -32.7119 -34.9258 -56.0996c-9.07422 -14.5752 -19.5244 -27.2256 -30.7988 -39.875c-16.1094 -18.374 -33.8359 -36.6328 -59.0752 -39.5967v-176.753c42.79 -3.7627 74.5088 -39.6758 120 -39.6758h21.2988
|
||||
c40.5244 0 57.124 22.1973 50.6006 61.3252c14.6113 8.00098 24.1514 33.9785 12.9248 53.625c19.3652 18.2246 17.7871 46.3809 4.9502 61.0498h91.0254zM88 64c0 13.2549 -10.7451 24 -24 24s-24 -10.7451 -24 -24s10.7451 -24 24 -24s24 10.7451 24 24z" />
|
||||
<glyph glyph-name="hand-point-left" unicode=""
|
||||
d="M0 227.2c0 45.0986 38.1006 83.2002 83.2002 83.2002h86.1758c-1.3623 6.91016 -2.17578 14.374 -2.17578 22.3994c0 47.9141 35.0723 83.2002 92 83.2002c45.3135 0 57.002 -48.5371 75.7061 -78.7852c7.73438 -12.4121 16.9951 -23.3154 25.8506 -33.2529
|
||||
l0.130859 -0.145508l0.128906 -0.148438c15.3213 -17.4746 23.2197 -23.668 30.1836 -23.668h2.67871c5.74707 4.95215 13.5361 8 22.1201 8h64c17.6729 0 32 -12.8936 32 -28.7998v-230.4c0 -15.9062 -14.3271 -28.7998 -32 -28.7998h-64
|
||||
c-8.58398 0 -16.373 3.04785 -22.1201 8h-2.67871c-28.6885 0 -67.1367 -40 -127.2 -40h-21.2988c-62.542 0 -98.8008 38.6582 -99.9404 91.1445c-12.4814 17.8135 -18.4922 40.7852 -15.9844 62.791c-3.49414 6.85938 -6.21582 14.3584 -7.92969 22.0645h-35.6465
|
||||
c-45.4355 0 -83.2002 37.584 -83.2002 83.2002zM48 227.2c0 -18.9756 16.2246 -35.2002 35.2002 -35.2002h91.0244c-12.8369 -14.6689 -14.415 -42.8252 4.9502 -61.0498c-11.2256 -19.6465 -1.68652 -45.624 12.9248 -53.625
|
||||
c-6.52246 -39.1279 10.0771 -61.3252 50.6016 -61.3252h21.2988c45.4912 0 77.21 35.9131 120 39.6768v176.752c-25.2393 2.96289 -42.9658 21.2227 -59.0752 39.5967c-11.2744 12.6494 -21.7246 25.2998 -30.7988 39.875
|
||||
c-14.4814 23.3877 -26.1318 56.0996 -34.9258 56.0996c-23.375 0 -44 -8.7998 -44 -35.2002c0 -35.2002 26.3994 -53.0752 26.3994 -70.3994h-158.399c-18.4248 0 -35.2002 -16.5 -35.2002 -35.2002zM448 88c-13.2549 0 -24 -10.7451 -24 -24s10.7451 -24 24 -24
|
||||
s24 10.7451 24 24s-10.7451 24 -24 24z" />
|
||||
<glyph glyph-name="hand-point-up" unicode="" horiz-adv-x="448"
|
||||
d="M105.6 364.8c0 45.0996 38.1016 83.2002 83.2002 83.2002c45.6162 0 83.2002 -37.7646 83.2002 -83.2002v-35.6465c7.70605 -1.71387 15.2051 -4.43555 22.0645 -7.92969c22.0059 2.50684 44.9775 -3.50293 62.791 -15.9844
|
||||
c52.4863 -1.14062 91.1445 -37.3984 91.1445 -99.9404v-21.2988c0 -60.0635 -40 -98.5117 -40 -127.2v-2.67871c4.95215 -5.74707 8 -13.5361 8 -22.1201v-64c0 -17.6729 -12.8936 -32 -28.7998 -32h-230.4c-15.9062 0 -28.7998 14.3271 -28.7998 32v64
|
||||
c0 8.58398 3.04785 16.373 8 22.1201v2.67871c0 6.96387 -6.19336 14.8623 -23.6689 30.1816l-0.148438 0.128906l-0.145508 0.130859c-9.93652 8.85645 -20.8398 18.1162 -33.2529 25.8506c-30.2471 18.7051 -78.7842 30.3936 -78.7842 75.707
|
||||
c0 56.9277 35.2861 92 83.2002 92c0.0283203 0 -0.0361328 0 -0.0078125 0c7.66602 0 15.1582 -0.748047 22.4072 -2.17578v86.1768zM224 364.8c0 18.9756 -16.2246 35.2002 -35.2002 35.2002c-18.7002 0 -35.2002 -16.7754 -35.2002 -35.2002v-158.399
|
||||
c-17.3242 0 -35.1992 26.3994 -70.3994 26.3994c-26.4004 0 -35.2002 -20.625 -35.2002 -44c0 -8.79395 32.7119 -20.4443 56.0996 -34.9258c14.5752 -9.07422 27.2256 -19.5244 39.875 -30.7988c18.374 -16.1094 36.6328 -33.8359 39.5967 -59.0752h176.753
|
||||
c3.7627 42.79 39.6758 74.5088 39.6758 120v21.2988c0 40.5244 -22.1973 57.124 -61.3252 50.6006c-8.00098 14.6113 -33.9785 24.1514 -53.625 12.9248c-18.2246 19.3652 -46.3809 17.7871 -61.0498 4.9502v91.0254zM352 24c-13.2549 0 -24 -10.7451 -24 -24
|
||||
s10.7451 -24 24 -24s24 10.7451 24 24s-10.7451 24 -24 24z" />
|
||||
<glyph glyph-name="hand-point-down" unicode="" horiz-adv-x="448"
|
||||
d="M188.8 -64c-45.0986 0 -83.2002 38.1006 -83.2002 83.2002v86.1758c-6.91016 -1.3623 -14.374 -2.17578 -22.3994 -2.17578c-47.9141 0 -83.2002 35.0723 -83.2002 92c0 45.3135 48.5371 57.002 78.7852 75.707c12.4121 7.73438 23.3154 16.9951 33.2529 25.8506
|
||||
l0.145508 0.130859l0.148438 0.128906c17.4746 15.3213 23.668 23.2197 23.668 30.1836v2.67871c-4.95215 5.74707 -8 13.5361 -8 22.1201v64c0 17.6729 12.8936 32 28.7998 32h230.4c15.9062 0 28.7998 -14.3271 28.7998 -32v-64.001
|
||||
c0 -8.58398 -3.04785 -16.373 -8 -22.1201v-2.67871c0 -28.6885 40 -67.1367 40 -127.2v-21.2988c0 -62.542 -38.6582 -98.8008 -91.1445 -99.9404c-17.8135 -12.4814 -40.7852 -18.4922 -62.791 -15.9844c-6.85938 -3.49414 -14.3584 -6.21582 -22.0645 -7.92969v-35.6465
|
||||
c0 -45.4355 -37.584 -83.2002 -83.2002 -83.2002zM188.8 -16c18.9756 0 35.2002 16.2246 35.2002 35.2002v91.0244c14.6689 -12.8369 42.8252 -14.415 61.0498 4.9502c19.6465 -11.2256 45.624 -1.68652 53.625 12.9248c39.1279 -6.52246 61.3252 10.0771 61.3252 50.6016
|
||||
v21.2988c0 45.4912 -35.9131 77.21 -39.6768 120h-176.752c-2.96289 -25.2393 -21.2227 -42.9658 -39.5967 -59.0752c-12.6494 -11.2744 -25.2998 -21.7246 -39.875 -30.7988c-23.3877 -14.4814 -56.0996 -26.1318 -56.0996 -34.9258c0 -23.375 8.7998 -44 35.2002 -44
|
||||
c35.2002 0 53.0752 26.3994 70.3994 26.3994v-158.399c0 -18.4248 16.5 -35.2002 35.2002 -35.2002zM328 384c0 -13.2549 10.7451 -24 24 -24s24 10.7451 24 24s-10.7451 24 -24 24s-24 -10.7451 -24 -24z" />
|
||||
<glyph glyph-name="copy" unicode="" horiz-adv-x="448"
|
||||
d="M433.941 382.059c8.68848 -8.68848 14.0586 -20.6943 14.0586 -33.9404v-268.118c0 -26.5098 -21.4902 -48 -48 -48h-80v-48c0 -26.5098 -21.4902 -48 -48 -48h-224c-26.5098 0 -48 21.4902 -48 48v320c0 26.5098 21.4902 48 48 48h80v48c0 26.5098 21.4902 48 48 48
|
||||
h172.118c13.2461 0 25.252 -5.37012 33.9404 -14.0586zM266 -16c3.31152 0 6 2.68848 6 6v42h-96c-26.5098 0 -48 21.4902 -48 48v224h-74c-3.31152 0 -6 -2.68848 -6 -6v-308c0 -3.31152 2.68848 -6 6 -6h212zM394 80c3.31152 0 6 2.68848 6 6v202h-88
|
||||
c-13.2549 0 -24 10.7451 -24 24v88h-106c-3.31152 0 -6 -2.68848 -6 -6v-308c0 -3.31152 2.68848 -6 6 -6h212zM400 336v9.63184c0 1.65527 -0.670898 3.15723 -1.75684 4.24316l-48.3682 48.3682c-1.12598 1.125 -2.65234 1.75684 -4.24316 1.75684h-9.63184v-64h64z" />
|
||||
<glyph glyph-name="save" unicode="" horiz-adv-x="448"
|
||||
d="M433.941 318.059c8.68848 -8.68848 14.0586 -20.6943 14.0586 -33.9404v-268.118c0 -26.5098 -21.4902 -48 -48 -48h-352c-26.5098 0 -48 21.4902 -48 48v352c0 26.5098 21.4902 48 48 48h268.118c13.2461 0 25.252 -5.37012 33.9404 -14.0586zM272 368h-128v-80h128v80z
|
||||
M394 16c3.31152 0 6 2.68848 6 6v259.632c0 1.65527 -0.670898 3.15723 -1.75684 4.24316l-78.2432 78.2432v-100.118c0 -13.2549 -10.7451 -24 -24 -24h-176c-13.2549 0 -24 10.7451 -24 24v104h-42c-3.31152 0 -6 -2.68848 -6 -6v-340c0 -3.31152 2.68848 -6 6 -6h340z
|
||||
M224 216c48.5234 0 88 -39.4766 88 -88s-39.4766 -88 -88 -88s-88 39.4766 -88 88s39.4766 88 88 88zM224 88c22.0557 0 40 17.9443 40 40s-17.9443 40 -40 40s-40 -17.9443 -40 -40s17.9443 -40 40 -40z" />
|
||||
<glyph glyph-name="square" unicode="" horiz-adv-x="448"
|
||||
d="M400 416c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h352zM394 16c3.2998 0 6 2.7002 6 6v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h340z" />
|
||||
<glyph glyph-name="envelope" unicode=""
|
||||
d="M464 384c26.5098 0 48 -21.4902 48 -48v-288c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v288c0 26.5098 21.4902 48 48 48h416zM464 336h-416v-40.8047c22.4248 -18.2627 58.1797 -46.6602 134.587 -106.49
|
||||
c16.834 -13.2422 50.2051 -45.0762 73.4131 -44.7012c23.2119 -0.371094 56.5723 31.4541 73.4131 44.7012c76.4189 59.8389 112.165 88.2305 134.587 106.49v40.8047zM48 48h416v185.601c-22.915 -18.252 -55.4189 -43.8691 -104.947 -82.6523
|
||||
c-22.5439 -17.748 -60.3359 -55.1787 -103.053 -54.9473c-42.9277 -0.231445 -81.2051 37.75 -103.062 54.9551c-49.5293 38.7842 -82.0244 64.3945 -104.938 82.6455v-185.602z" />
|
||||
<glyph glyph-name="lightbulb" unicode="" horiz-adv-x="352"
|
||||
d="M176 368c8.83984 0 16 -7.16016 16 -16s-7.16016 -16 -16 -16c-35.2803 0 -64 -28.7002 -64 -64c0 -8.83984 -7.16016 -16 -16 -16s-16 7.16016 -16 16c0 52.9404 43.0596 96 96 96zM96.0596 -11.1699l-0.0400391 43.1797h159.961l-0.0507812 -43.1797
|
||||
c-0.00976562 -3.13965 -0.939453 -6.21973 -2.67969 -8.83984l-24.5098 -36.8398c-2.95996 -4.45996 -7.95996 -7.14062 -13.3203 -7.14062h-78.8496c-5.35059 0 -10.3506 2.68066 -13.3203 7.14062l-24.5098 36.8398c-1.75 2.62012 -2.68066 5.68945 -2.68066 8.83984z
|
||||
M176 448c97.2002 0 176 -78.7998 176 -176c0 -44.3701 -16.4502 -84.8496 -43.5498 -115.79c-16.6406 -18.9795 -42.7402 -58.79 -52.4199 -92.1602v-0.0498047h-48v0.0996094c0.00488281 4.98145 0.790039 9.78809 2.21973 14.3008
|
||||
c5.67969 17.9893 22.9902 64.8496 62.0996 109.46c20.4102 23.29 31.6504 53.1699 31.6504 84.1396c0 70.5801 -57.4199 128 -128 128c-68.2803 0 -128.15 -54.3604 -127.95 -128c0.0898438 -30.9902 11.0703 -60.71 31.6104 -84.1396
|
||||
c39.3496 -44.9004 56.5801 -91.8604 62.1699 -109.67c1.42969 -4.56055 2.13965 -9.30078 2.15039 -14.0703v-0.120117h-48v0.0595703c-9.68066 33.3604 -35.7803 73.1709 -52.4209 92.1602c-27.1094 30.9307 -43.5596 71.4102 -43.5596 115.78
|
||||
c0 93.0303 73.7197 176 176 176z" />
|
||||
<glyph glyph-name="bell" unicode="" horiz-adv-x="448"
|
||||
d="M439.39 85.71c6 -6.44043 8.66016 -14.1602 8.61035 -21.71c-0.0996094 -16.4004 -12.9805 -32 -32.0996 -32h-383.801c-19.1191 0 -31.9893 15.5996 -32.0996 32c-0.0498047 7.5498 2.61035 15.2598 8.61035 21.71c19.3193 20.7598 55.4697 51.9902 55.4697 154.29
|
||||
c0 77.7002 54.4795 139.9 127.939 155.16v20.8398c0 17.6699 14.3203 32 31.9805 32s31.9805 -14.3301 31.9805 -32v-20.8398c73.46 -15.2598 127.939 -77.46 127.939 -155.16c0 -102.3 36.1504 -133.53 55.4697 -154.29zM67.5303 80h312.939
|
||||
c-21.2197 27.96 -44.4199 74.3203 -44.5293 159.42c0 0.200195 0.0595703 0.379883 0.0595703 0.580078c0 61.8604 -50.1396 112 -112 112s-112 -50.1396 -112 -112c0 -0.200195 0.0595703 -0.379883 0.0595703 -0.580078
|
||||
c-0.109375 -85.0898 -23.3096 -131.45 -44.5293 -159.42zM224 -64c-35.3203 0 -63.9697 28.6504 -63.9697 64h127.939c0 -35.3496 -28.6494 -64 -63.9697 -64z" />
|
||||
<glyph glyph-name="hospital" unicode="" horiz-adv-x="448"
|
||||
d="M128 204v40c0 6.62695 5.37305 12 12 12h40c6.62695 0 12 -5.37305 12 -12v-40c0 -6.62695 -5.37305 -12 -12 -12h-40c-6.62695 0 -12 5.37305 -12 12zM268 192c-6.62695 0 -12 5.37305 -12 12v40c0 6.62695 5.37305 12 12 12h40c6.62695 0 12 -5.37305 12 -12v-40
|
||||
c0 -6.62695 -5.37305 -12 -12 -12h-40zM192 108c0 -6.62695 -5.37305 -12 -12 -12h-40c-6.62695 0 -12 5.37305 -12 12v40c0 6.62695 5.37305 12 12 12h40c6.62695 0 12 -5.37305 12 -12v-40zM268 96c-6.62695 0 -12 5.37305 -12 12v40c0 6.62695 5.37305 12 12 12h40
|
||||
c6.62695 0 12 -5.37305 12 -12v-40c0 -6.62695 -5.37305 -12 -12 -12h-40zM448 -28v-36h-448v36c0 6.62695 5.37305 12 12 12h19.5v378.965c0 11.6172 10.7451 21.0352 24 21.0352h88.5v40c0 13.2549 10.7451 24 24 24h112c13.2549 0 24 -10.7451 24 -24v-40h88.5
|
||||
c13.2549 0 24 -9.41797 24 -21.0352v-378.965h19.5c6.62695 0 12 -5.37305 12 -12zM79.5 -15h112.5v67c0 6.62695 5.37305 12 12 12h40c6.62695 0 12 -5.37305 12 -12v-67h112.5v351h-64.5v-24c0 -13.2549 -10.7451 -24 -24 -24h-112c-13.2549 0 -24 10.7451 -24 24v24
|
||||
h-64.5v-351zM266 384h-26v26c0 3.31152 -2.68848 6 -6 6h-20c-3.31152 0 -6 -2.68848 -6 -6v-26h-26c-3.31152 0 -6 -2.68848 -6 -6v-20c0 -3.31152 2.68848 -6 6 -6h26v-26c0 -3.31152 2.68848 -6 6 -6h20c3.31152 0 6 2.68848 6 6v26h26c3.31152 0 6 2.68848 6 6v20
|
||||
c0 3.31152 -2.68848 6 -6 6z" />
|
||||
<glyph glyph-name="plus-square" unicode="" horiz-adv-x="448"
|
||||
d="M352 208v-32c0 -6.59961 -5.40039 -12 -12 -12h-88v-88c0 -6.59961 -5.40039 -12 -12 -12h-32c-6.59961 0 -12 5.40039 -12 12v88h-88c-6.59961 0 -12 5.40039 -12 12v32c0 6.59961 5.40039 12 12 12h88v88c0 6.59961 5.40039 12 12 12h32c6.59961 0 12 -5.40039 12 -12
|
||||
v-88h88c6.59961 0 12 -5.40039 12 -12zM448 368v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h352c26.5 0 48 -21.5 48 -48zM400 22v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340
|
||||
c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
||||
<glyph glyph-name="circle" unicode=""
|
||||
d="M256 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM256 -8c110.5 0 200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200s89.5 -200 200 -200z" />
|
||||
<glyph glyph-name="smile" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32
|
||||
s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM332 135.4c8.5 10.1992 23.7002 11.5 33.7998 3.09961c10.2002 -8.5 11.6006 -23.5996 3.10059 -33.7998
|
||||
c-30 -36 -74.1006 -56.6006 -120.9 -56.6006s-90.9004 20.6006 -120.9 56.6006c-8.39941 10.2002 -7.09961 25.2998 3.10059 33.7998c10.0996 8.40039 25.2998 7.09961 33.7998 -3.09961c20.7998 -25.1006 51.5 -39.4004 84 -39.4004s63.2002 14.4004 84 39.4004z" />
|
||||
<glyph glyph-name="frown" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32
|
||||
s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM248 144c40.2002 0 78 -17.7002 103.8 -48.5996c8.40039 -10.2002 7.10059 -25.3008 -3.09961 -33.8008
|
||||
c-10.7002 -8.7998 -25.7002 -6.59961 -33.7998 3.10059c-16.6006 20 -41 31.3994 -66.9004 31.3994s-50.2998 -11.5 -66.9004 -31.3994c-8.5 -10.2002 -23.5996 -11.5 -33.7998 -3.10059c-10.2002 8.5 -11.5996 23.6006 -3.09961 33.8008
|
||||
c25.7998 30.8994 63.5996 48.5996 103.8 48.5996z" />
|
||||
<glyph glyph-name="meh" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32
|
||||
s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM336 128c13.2002 0 24 -10.7998 24 -24s-10.7998 -24 -24 -24h-176c-13.2002 0 -24 10.7998 -24 24s10.7998 24 24 24h176z
|
||||
" />
|
||||
<glyph glyph-name="keyboard" unicode="" horiz-adv-x="576"
|
||||
d="M528 384c26.5098 0 48 -21.4902 48 -48v-288c0 -26.5098 -21.4902 -48 -48 -48h-480c-26.5098 0 -48 21.4902 -48 48v288c0 26.5098 21.4902 48 48 48h480zM536 48v288c0 4.41113 -3.58887 8 -8 8h-480c-4.41113 0 -8 -3.58887 -8 -8v-288c0 -4.41113 3.58887 -8 8 -8
|
||||
h480c4.41113 0 8 3.58887 8 8zM170 178c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM266 178c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28
|
||||
c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM362 178c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM458 178c0 -6.62695 -5.37305 -12 -12 -12h-28
|
||||
c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM122 96c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM506 96
|
||||
c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM122 260c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28
|
||||
c6.62695 0 12 -5.37305 12 -12v-28zM218 260c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM314 260c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28
|
||||
c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM410 260c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM506 260c0 -6.62695 -5.37305 -12 -12 -12h-28
|
||||
c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM408 102c0 -6.62695 -5.37305 -12 -12 -12h-216c-6.62695 0 -12 5.37305 -12 12v16c0 6.62695 5.37305 12 12 12h216c6.62695 0 12 -5.37305 12 -12v-16z" />
|
||||
<glyph glyph-name="calendar" unicode="" horiz-adv-x="448"
|
||||
d="M400 384c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h48v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h128v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12
|
||||
v-52h48zM394 -16c3.2998 0 6 2.7002 6 6v298h-352v-298c0 -3.2998 2.7002 -6 6 -6h340z" />
|
||||
<glyph glyph-name="play-circle" unicode=""
|
||||
d="M371.7 210c16.3994 -9.2002 16.3994 -32.9004 0 -42l-176 -101c-15.9004 -8.7998 -35.7002 2.59961 -35.7002 21v208c0 18.5 19.9004 29.7998 35.7002 21zM504 192c0 -137 -111 -248 -248 -248s-248 111 -248 248s111 248 248 248s248 -111 248 -248zM56 192
|
||||
c0 -110.5 89.5 -200 200 -200s200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200z" />
|
||||
<glyph glyph-name="minus-square" unicode="" horiz-adv-x="448"
|
||||
d="M108 164c-6.59961 0 -12 5.40039 -12 12v32c0 6.59961 5.40039 12 12 12h232c6.59961 0 12 -5.40039 12 -12v-32c0 -6.59961 -5.40039 -12 -12 -12h-232zM448 368v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h352
|
||||
c26.5 0 48 -21.5 48 -48zM400 22v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
||||
<glyph glyph-name="check-square" unicode="" horiz-adv-x="448"
|
||||
d="M400 416c26.5098 0 48 -21.4902 48 -48v-352c0 -26.5098 -21.4902 -48 -48 -48h-352c-26.5098 0 -48 21.4902 -48 48v352c0 26.5098 21.4902 48 48 48h352zM400 16v352h-352v-352h352zM364.136 257.724l-172.589 -171.204
|
||||
c-4.70508 -4.66699 -12.3027 -4.63672 -16.9697 0.0683594l-90.7812 91.5156c-4.66699 4.70508 -4.63672 12.3037 0.0693359 16.9717l22.7188 22.5361c4.70508 4.66699 12.3027 4.63672 16.9697 -0.0693359l59.792 -60.2773l141.353 140.217
|
||||
c4.70508 4.66699 12.3027 4.63672 16.9697 -0.0683594l22.5361 -22.7178c4.66699 -4.70605 4.63672 -12.3047 -0.0683594 -16.9717z" />
|
||||
<glyph glyph-name="share-square" unicode="" horiz-adv-x="576"
|
||||
d="M561.938 289.94c18.75 -18.7402 18.75 -49.1406 0 -67.8809l-143.998 -144c-29.9727 -29.9727 -81.9404 -9.05273 -81.9404 33.9404v53.7998c-101.266 -7.83691 -99.625 -31.6406 -84.1104 -78.7598c14.2285 -43.0889 -33.4736 -79.248 -71.0195 -55.7402
|
||||
c-51.6924 32.3057 -84.8701 83.0635 -84.8701 144.76c0 39.3408 12.2197 72.7402 36.3301 99.3008c19.8398 21.8398 47.7402 38.4697 82.9102 49.4199c36.7295 11.4395 78.3096 16.1094 120.76 17.9893v57.1982c0 42.9355 51.9258 63.9541 81.9404 33.9404zM384 112l144 144
|
||||
l-144 144v-104.09c-110.86 -0.90332 -240 -10.5166 -240 -119.851c0 -52.1396 32.79 -85.6094 62.3096 -104.06c-39.8174 120.65 48.999 141.918 177.69 143.84v-103.84zM408.74 27.5068c7.4375 2.125 14.5508 5.30566 20.9736 9.30273
|
||||
c7.97656 4.95215 18.2861 -0.825195 18.2861 -10.2139v-42.5957c0 -26.5098 -21.4902 -48 -48 -48h-352c-26.5098 0 -48 21.4902 -48 48v352c0 26.5098 21.4902 48 48 48h132c6.62695 0 12 -5.37305 12 -12v-4.48633c0 -4.91699 -2.9873 -9.36914 -7.56934 -11.1514
|
||||
c-13.7021 -5.33105 -26.3955 -11.5371 -38.0498 -18.585c-1.82715 -1.11523 -3.98633 -1.76953 -6.28027 -1.77734h-86.1006c-3.31152 0 -6 -2.68848 -6 -6v-340c0 -3.31152 2.68848 -6 6 -6h340c3.31152 0 6 2.68848 6 6v25.9658c0 5.37012 3.5791 10.0596 8.74023 11.541z
|
||||
" />
|
||||
<glyph glyph-name="compass" unicode="" horiz-adv-x="496"
|
||||
d="M347.94 318.14c16.6592 7.61035 33.8096 -9.54004 26.1992 -26.1992l-65.9697 -144.341c-3.19238 -6.9834 -8.78613 -12.5771 -15.7695 -15.7695l-144.341 -65.9697c-16.6592 -7.61035 -33.8096 9.5498 -26.1992 26.1992l65.9697 144.341
|
||||
c3.19238 6.9834 8.78613 12.5771 15.7695 15.7695zM270.58 169.42c12.4697 12.4697 12.4697 32.6904 0 45.1602s-32.6904 12.4697 -45.1602 0s-12.4697 -32.6904 0 -45.1602s32.6904 -12.4697 45.1602 0zM248 440c136.97 0 248 -111.03 248 -248s-111.03 -248 -248 -248
|
||||
s-248 111.03 -248 248s111.03 248 248 248zM248 -8c110.28 0 200 89.7197 200 200s-89.7197 200 -200 200s-200 -89.7197 -200 -200s89.7197 -200 200 -200z" />
|
||||
<glyph glyph-name="caret-square-down" unicode="" horiz-adv-x="448"
|
||||
d="M125.1 240h197.801c10.6992 0 16.0996 -13 8.5 -20.5l-98.9004 -98.2998c-4.7002 -4.7002 -12.2002 -4.7002 -16.9004 0l-98.8994 98.2998c-7.7002 7.5 -2.2998 20.5 8.39941 20.5zM448 368v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352
|
||||
c0 26.5 21.5 48 48 48h352c26.5 0 48 -21.5 48 -48zM400 22v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
||||
<glyph glyph-name="caret-square-up" unicode="" horiz-adv-x="448"
|
||||
d="M322.9 144h-197.801c-10.6992 0 -16.0996 13 -8.5 20.5l98.9004 98.2998c4.7002 4.7002 12.2002 4.7002 16.9004 0l98.8994 -98.2998c7.7002 -7.5 2.2998 -20.5 -8.39941 -20.5zM448 368v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352
|
||||
c0 26.5 21.5 48 48 48h352c26.5 0 48 -21.5 48 -48zM400 22v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
||||
<glyph glyph-name="caret-square-right" unicode="" horiz-adv-x="448"
|
||||
d="M176 93.0996v197.801c0 10.6992 13 16.0996 20.5 8.5l98.2998 -98.9004c4.7002 -4.7002 4.7002 -12.2002 0 -16.9004l-98.2998 -98.8994c-7.5 -7.7002 -20.5 -2.2998 -20.5 8.39941zM448 368v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352
|
||||
c0 26.5 21.5 48 48 48h352c26.5 0 48 -21.5 48 -48zM400 22v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
||||
<glyph glyph-name="file" unicode="" horiz-adv-x="384"
|
||||
d="M369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM332.1 320l-76.0996 76.0996v-76.0996h76.0996zM48 -16h288v288
|
||||
h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416z" />
|
||||
<glyph glyph-name="file-alt" unicode="" horiz-adv-x="384"
|
||||
d="M288 200v-28c0 -6.59961 -5.40039 -12 -12 -12h-168c-6.59961 0 -12 5.40039 -12 12v28c0 6.59961 5.40039 12 12 12h168c6.59961 0 12 -5.40039 12 -12zM276 128c6.59961 0 12 -5.40039 12 -12v-28c0 -6.59961 -5.40039 -12 -12 -12h-168c-6.59961 0 -12 5.40039 -12 12
|
||||
v28c0 6.59961 5.40039 12 12 12h168zM384 316.1v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996l83.9004 -83.9004c9 -8.90039 14.0996 -21.2002 14.0996 -33.9004z
|
||||
M256 396.1v-76.0996h76.0996zM336 -16v288h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416h288z" />
|
||||
<glyph glyph-name="thumbs-up" unicode=""
|
||||
d="M466.27 161.31c4.6748 -22.6465 0.864258 -44.5371 -8.98926 -62.9893c2.95898 -23.8682 -4.02148 -48.5654 -17.3398 -66.9902c-0.954102 -55.9072 -35.8232 -95.3301 -112.94 -95.3301c-7 0 -15 0.00976562 -22.2197 0.00976562
|
||||
c-102.742 0 -133.293 38.9395 -177.803 39.9404c-3.56934 -13.7764 -16.085 -23.9502 -30.9775 -23.9502h-64c-17.6729 0 -32 14.3271 -32 32v240c0 17.6729 14.3271 32 32 32h98.7598c19.1455 16.9531 46.0137 60.6533 68.7598 83.4004
|
||||
c13.667 13.667 10.1533 108.6 71.7607 108.6c57.5801 0 95.2695 -31.9355 95.2695 -104.73c0 -18.4092 -3.92969 -33.7295 -8.84961 -46.5391h36.4795c48.6025 0 85.8203 -41.5654 85.8203 -85.5801c0 -19.1504 -4.95996 -34.9902 -13.7305 -49.8408zM404.52 107.48
|
||||
c21.5811 20.3838 18.6992 51.0645 5.21094 65.6191c9.44922 0 22.3594 18.9102 22.2695 37.8105c-0.0898438 18.9102 -16.71 37.8203 -37.8203 37.8203h-103.989c0 37.8193 28.3594 55.3691 28.3594 94.5391c0 23.75 0 56.7305 -47.2695 56.7305
|
||||
c-18.9102 -18.9102 -9.45996 -66.1797 -37.8203 -94.54c-26.5596 -26.5703 -66.1797 -97.46 -94.54 -97.46h-10.9199v-186.17c53.6113 0 100.001 -37.8203 171.64 -37.8203h37.8203c35.5117 0 60.8203 17.1201 53.1201 65.9004
|
||||
c15.2002 8.16016 26.5 36.4395 13.9395 57.5703zM88 16c0 13.2549 -10.7451 24 -24 24s-24 -10.7451 -24 -24s10.7451 -24 24 -24s24 10.7451 24 24z" />
|
||||
<glyph glyph-name="thumbs-down" unicode=""
|
||||
d="M466.27 222.69c8.77051 -14.8506 13.7305 -30.6904 13.7305 -49.8408c0 -44.0146 -37.2178 -85.5801 -85.8203 -85.5801h-36.4795c4.91992 -12.8096 8.84961 -28.1299 8.84961 -46.5391c0 -72.7949 -37.6895 -104.73 -95.2695 -104.73
|
||||
c-61.6074 0 -58.0938 94.9326 -71.7607 108.6c-22.7461 22.7471 -49.6133 66.4473 -68.7598 83.4004h-7.05176c-5.5332 -9.56152 -15.8662 -16 -27.708 -16h-64c-17.6729 0 -32 14.3271 -32 32v240c0 17.6729 14.3271 32 32 32h64c8.11328 0 15.5146 -3.02539 21.1553 -8
|
||||
h10.8447c40.9971 0 73.1953 39.9902 176.78 39.9902c7.21973 0 15.2197 0.00976562 22.2197 0.00976562c77.1172 0 111.986 -39.4229 112.94 -95.3301c13.3184 -18.4248 20.2979 -43.1221 17.3398 -66.9902c9.85352 -18.4521 13.6641 -40.3428 8.98926 -62.9893zM64 152
|
||||
c13.2549 0 24 10.7451 24 24s-10.7451 24 -24 24s-24 -10.7451 -24 -24s10.7451 -24 24 -24zM394.18 135.27c21.1104 0 37.7305 18.9102 37.8203 37.8203c0.0898438 18.9004 -12.8203 37.8105 -22.2695 37.8105c13.4883 14.5547 16.3701 45.2354 -5.21094 65.6191
|
||||
c12.5605 21.1309 1.26074 49.4102 -13.9395 57.5703c7.7002 48.7803 -17.6084 65.9004 -53.1201 65.9004h-37.8203c-71.6387 0 -118.028 -37.8203 -171.64 -37.8203v-186.17h10.9199c28.3604 0 67.9805 -70.8896 94.54 -97.46
|
||||
c28.3604 -28.3604 18.9102 -75.6299 37.8203 -94.54c47.2695 0 47.2695 32.9805 47.2695 56.7305c0 39.1699 -28.3594 56.7197 -28.3594 94.5391h103.989z" />
|
||||
<glyph glyph-name="sun" unicode=""
|
||||
d="M494.2 226.1c11.2002 -7.59961 17.7998 -20.0996 17.8994 -33.6992c0 -13.4004 -6.69922 -26 -17.7998 -33.5l-59.7998 -40.5l13.7002 -71c2.5 -13.2002 -1.60059 -26.8008 -11.1006 -36.3008s-22.8994 -13.7998 -36.2998 -11.0996l-70.8994 13.7002l-40.4004 -59.9004
|
||||
c-7.5 -11.0996 -20.0996 -17.7998 -33.5 -17.7998s-26 6.7002 -33.5 17.9004l-40.4004 59.8994l-70.7998 -13.7002c-13.3994 -2.59961 -26.7998 1.60059 -36.2998 11.1006s-13.7002 23.0996 -11.0996 36.2998l13.6992 71l-59.7998 40.5
|
||||
c-11.0996 7.5 -17.7998 20 -17.7998 33.5s6.59961 26 17.7998 33.5996l59.7998 40.5l-13.6992 71c-2.60059 13.2002 1.59961 26.7002 11.0996 36.3008c9.5 9.59961 23 13.6992 36.2998 11.1992l70.7998 -13.6992l40.4004 59.8994c15.0996 22.2998 51.9004 22.2998 67 0
|
||||
l40.4004 -59.8994l70.8994 13.6992c13 2.60059 26.6006 -1.59961 36.2002 -11.0996c9.5 -9.59961 13.7002 -23.2002 11.0996 -36.4004l-13.6992 -71zM381.3 140.5l76.7998 52.0996l-76.7998 52l17.6006 91.1006l-91 -17.6006l-51.9004 76.9004l-51.7998 -76.7998
|
||||
l-91 17.5996l17.5996 -91.2002l-76.7998 -52l76.7998 -52l-17.5996 -91.1992l90.8994 17.5996l51.9004 -77l51.9004 76.9004l91 -17.6006zM256 296c57.2998 0 104 -46.7002 104 -104s-46.7002 -104 -104 -104s-104 46.7002 -104 104s46.7002 104 104 104zM256 136
|
||||
c30.9004 0 56 25.0996 56 56s-25.0996 56 -56 56s-56 -25.0996 -56 -56s25.0996 -56 56 -56z" />
|
||||
<glyph glyph-name="moon" unicode=""
|
||||
d="M279.135 -64c-141.424 0 -256 114.64 -256 256c0 141.425 114.641 256 256 256c16.0342 -0.00292969 31.5078 -1.46875 46.7354 -4.27734c44.0205 -8.13086 53.7666 -66.8691 15.0215 -88.9189c-41.374 -23.5439 -67.4336 -67.4121 -67.4336 -115.836
|
||||
c0 -83.5234 75.9238 -146.475 158.272 -130.792c43.6904 8.32129 74.5186 -42.5693 46.248 -77.4004c-47.8613 -58.9717 -120.088 -94.7754 -198.844 -94.7754zM279.135 400c-114.875 0 -208 -93.125 -208 -208s93.125 -208 208 -208
|
||||
c65.2314 0 123.439 30.0361 161.575 77.0244c-111.611 -21.2568 -215.252 64.0957 -215.252 177.943c0 67.5127 36.9326 126.392 91.6934 157.555c-12.3271 2.27637 -25.0312 3.47754 -38.0166 3.47754z" />
|
||||
<glyph glyph-name="caret-square-left" unicode="" horiz-adv-x="448"
|
||||
d="M272 290.9v-197.801c0 -10.6992 -13 -16.0996 -20.5 -8.5l-98.2998 98.9004c-4.7002 4.7002 -4.7002 12.2002 0 16.9004l98.2998 98.8994c7.5 7.7002 20.5 2.2998 20.5 -8.39941zM448 368v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352
|
||||
c0 26.5 21.5 48 48 48h352c26.5 0 48 -21.5 48 -48zM400 22v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
||||
<glyph glyph-name="dot-circle" unicode=""
|
||||
d="M256 392c-110.549 0 -200 -89.4678 -200 -200c0 -110.549 89.4678 -200 200 -200c110.549 0 200 89.4678 200 200c0 110.549 -89.4678 200 -200 200zM256 440c136.967 0 248 -111.033 248 -248s-111.033 -248 -248 -248s-248 111.033 -248 248s111.033 248 248 248z
|
||||
M256 272c44.1826 0 80 -35.8174 80 -80s-35.8174 -80 -80 -80s-80 35.8174 -80 80s35.8174 80 80 80z" />
|
||||
<glyph glyph-name="building" unicode="" horiz-adv-x="448"
|
||||
d="M128 300v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12zM268 288c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40
|
||||
c0 -6.59961 -5.40039 -12 -12 -12h-40zM140 192c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12h-40zM268 192c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40
|
||||
c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12h-40zM192 108c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40zM268 96c-6.59961 0 -12 5.40039 -12 12v40
|
||||
c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12h-40zM448 -28v-36h-448v36c0 6.59961 5.40039 12 12 12h19.5v440c0 13.2998 10.7002 24 24 24h337c13.2998 0 24 -10.7002 24 -24v-440h19.5
|
||||
c6.59961 0 12 -5.40039 12 -12zM79.5 -15h112.5v67c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-67h112.5v414l-288.5 1z" />
|
||||
<glyph glyph-name="file-pdf" unicode="" horiz-adv-x="384"
|
||||
d="M369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM332.1 320l-76.0996 76.0996v-76.0996h76.0996zM48 -16h288v288
|
||||
h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416zM298.2 127.7c10.5 -10.5 8 -38.7002 -17.5 -38.7002c-14.7998 0 -36.9004 6.7998 -55.7998 17c-21.6006 -3.59961 -46 -12.7002 -68.4004 -20.0996c-50.0996 -86.4004 -79.4004 -47 -76.0996 -31.2002
|
||||
c4 20 31 35.8994 51 46.2002c10.5 18.3994 25.3994 50.5 35.3994 74.3994c-7.39941 28.6006 -11.3994 51 -7 67.1006c4.7998 17.6992 38.4004 20.2998 42.6006 -5.90039c4.69922 -15.4004 -1.5 -39.9004 -5.40039 -56c8.09961 -21.2998 19.5996 -35.7998 36.7998 -46.2998
|
||||
c17.4004 2.2002 52.2002 5.5 64.4004 -6.5zM100.1 49.9004c0 -0.700195 11.4004 4.69922 30.4004 35c-5.90039 -5.5 -25.2998 -21.3008 -30.4004 -35zM181.7 240.5c-2.5 0 -2.60059 -26.9004 1.7998 -40.7998c4.90039 8.7002 5.59961 40.7998 -1.7998 40.7998zM157.3 103.9
|
||||
c15.9004 6.09961 34 14.8994 54.7998 19.1992c-11.1992 8.30078 -21.7998 20.4004 -30.0996 35.5c-6.7002 -17.6992 -15 -37.7998 -24.7002 -54.6992zM288.9 108.9c3.59961 2.39941 -2.2002 10.3994 -37.3008 7.7998c32.3008 -13.7998 37.3008 -7.7998 37.3008 -7.7998z" />
|
||||
<glyph glyph-name="file-word" unicode="" horiz-adv-x="384"
|
||||
d="M369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM332.1 320l-76.0996 76.0996v-76.0996h76.0996zM48 -16h288v288
|
||||
h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416zM268.1 192v0.200195h15.8008c7.7998 0 13.5 -7.2998 11.5996 -14.9004c-4.2998 -17 -13.7002 -54.0996 -34.5 -136c-1.2998 -5.39941 -6.09961 -9.09961 -11.5996 -9.09961h-24.7002
|
||||
c-5.5 0 -10.2998 3.7998 -11.6006 9.09961c-5.2998 20.9004 -17.7998 71 -17.8994 71.4004l-2.90039 17.2998c-0.5 -5.2998 -1.5 -11.0996 -3 -17.2998l-17.8994 -71.4004c-1.30078 -5.39941 -6.10059 -9.09961 -11.6006 -9.09961h-25.2002
|
||||
c-5.59961 0 -10.3994 3.7002 -11.6992 9.09961c-6.5 26.5 -25.2002 103.4 -33.2002 136c-1.7998 7.5 3.89941 14.7998 11.7002 14.7998h16.7998c5.7998 0 10.7002 -4.09961 11.7998 -9.69922c5 -25.7002 18.4004 -93.8008 19.0996 -99
|
||||
c0.300781 -1.7002 0.400391 -3.10059 0.5 -4.2002c0.800781 7.5 0.400391 4.7002 24.8008 103.7c1.39941 5.2998 6.19922 9.09961 11.6992 9.09961h13.3008c5.59961 0 10.3994 -3.7998 11.6992 -9.2002c23.9004 -99.7002 22.8008 -94.3994 23.6006 -99.5
|
||||
c0.299805 -1.7002 0.5 -3.09961 0.700195 -4.2998c0.599609 8.09961 0.399414 5.7998 21 103.5c1.09961 5.5 6 9.5 11.6992 9.5z" />
|
||||
<glyph glyph-name="file-excel" unicode="" horiz-adv-x="384"
|
||||
d="M369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM332.1 320l-76.0996 76.0996v-76.0996h76.0996zM48 -16h288v288
|
||||
h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416zM260 224c9.2002 0 15 -10 10.2998 -18c-16 -27.5 -45.5996 -76.9004 -46.2998 -78l46.4004 -78c4.59961 -8 -1.10059 -18 -10.4004 -18h-28.7998c-4.40039 0 -8.5 2.40039 -10.6006 6.2998
|
||||
c-22.6992 41.7998 -13.6992 27.5 -28.5996 57.7002c-5.59961 -12.7002 -6.90039 -17.7002 -28.5996 -57.7002c-2.10059 -3.89941 -6.10059 -6.2998 -10.5 -6.2998h-28.9004c-9.2998 0 -15.0996 10 -10.4004 18l46.3008 78l-46.3008 78c-4.59961 8 1.10059 18 10.4004 18
|
||||
h28.9004c4.39941 0 8.5 -2.40039 10.5996 -6.2998c21.7002 -40.4004 14.7002 -28.6006 28.5996 -57.7002c6.40039 15.2998 10.6006 24.5996 28.6006 57.7002c2.09961 3.89941 6.09961 6.2998 10.5 6.2998h28.7998z" />
|
||||
<glyph glyph-name="file-powerpoint" unicode="" horiz-adv-x="384"
|
||||
d="M369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM332.1 320l-76.0996 76.0996v-76.0996h76.0996zM48 -16h288v288
|
||||
h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416zM120 44v168c0 6.59961 5.40039 12 12 12h69.2002c36.7002 0 62.7998 -27 62.7998 -66.2998c0 -74.2998 -68.7002 -66.5 -95.5 -66.5v-47.2002c0 -6.59961 -5.40039 -12 -12 -12h-24.5c-6.59961 0 -12 5.40039 -12 12z
|
||||
M168.5 131.4h23c7.90039 0 13.9004 2.39941 18.0996 7.19922c8.5 9.80078 8.40039 28.5 0.100586 37.8008c-4.10059 4.59961 -9.90039 7 -17.4004 7h-23.8994v-52h0.0996094z" />
|
||||
<glyph glyph-name="file-image" unicode="" horiz-adv-x="384"
|
||||
d="M369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM332.1 320l-76.0996 76.0996v-76.0996h76.0996zM48 -16h288v288
|
||||
h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416zM80 32v64l39.5 39.5c4.7002 4.7002 12.2998 4.7002 17 0l39.5 -39.5l87.5 87.5c4.7002 4.7002 12.2998 4.7002 17 0l23.5 -23.5v-128h-224zM128 272c26.5 0 48 -21.5 48 -48s-21.5 -48 -48 -48s-48 21.5 -48 48
|
||||
s21.5 48 48 48z" />
|
||||
<glyph glyph-name="file-archive" unicode="" horiz-adv-x="384"
|
||||
d="M128.3 288h32v-32h-32v32zM192.3 384v-32h-32v32h32zM128.3 352h32v-32h-32v32zM192.3 320v-32h-32v32h32zM369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1
|
||||
c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM256 396.1v-76.0996h76.0996zM336 -16v288h-104c-13.2998 0 -24 10.7002 -24 24v104h-48.2998v-16h-32v16h-79.7002v-416h288zM194.2 182.3l17.2998 -87.7002c6.40039 -32.3994 -18.4004 -62.5996 -51.5 -62.5996
|
||||
c-33.2002 0 -58 30.4004 -51.4004 62.9004l19.7002 97.0996v32h32v-32h22.1006c5.7998 0 10.6992 -4.09961 11.7998 -9.7002zM160.3 57.9004c17.9004 0 32.4004 12.0996 32.4004 27c0 14.8994 -14.5 27 -32.4004 27c-17.8994 0 -32.3994 -12.1006 -32.3994 -27
|
||||
c0 -14.9004 14.5 -27 32.3994 -27zM192.3 256v-32h-32v32h32z" />
|
||||
<glyph glyph-name="file-audio" unicode="" horiz-adv-x="384"
|
||||
d="M369.941 350.059c8.68848 -8.68848 14.0586 -20.6943 14.0586 -33.9404v-332.118c0 -26.5098 -21.4902 -48 -48 -48h-288c-26.5098 0 -48 21.4902 -48 48v416c0 26.5098 21.4902 48 48 48h204.118c13.2461 0 25.252 -5.37012 33.9404 -14.0586zM332.118 320
|
||||
l-76.1182 76.1182v-76.1182h76.1182zM48 -16h288v288h-104c-13.2549 0 -24 10.7451 -24 24v104h-160v-416zM192 60.0244c0 -10.6914 -12.9258 -16.0459 -20.4854 -8.48535l-35.5146 35.9746h-28c-6.62695 0 -12 5.37305 -12 12v56c0 6.62695 5.37305 12 12 12h28
|
||||
l35.5146 36.9473c7.56055 7.56055 20.4854 2.20605 20.4854 -8.48535v-135.951zM233.201 107.154c9.05078 9.29688 9.05957 24.1328 0.000976562 33.4385c-22.1494 22.752 12.2344 56.2461 34.3945 33.4814c27.1982 -27.9404 27.2119 -72.4443 0.000976562 -100.401
|
||||
c-21.793 -22.3857 -56.9463 10.3154 -34.3965 33.4814z" />
|
||||
<glyph glyph-name="file-video" unicode="" horiz-adv-x="384"
|
||||
d="M369.941 350.059c8.68848 -8.68848 14.0586 -20.6943 14.0586 -33.9404v-332.118c0 -26.5098 -21.4902 -48 -48 -48h-288c-26.5098 0 -48 21.4902 -48 48v416c0 26.5098 21.4902 48 48 48h204.118c13.2461 0 25.252 -5.37012 33.9404 -14.0586zM332.118 320
|
||||
l-76.1182 76.1182v-76.1182h76.1182zM48 -16h288v288h-104c-13.2549 0 -24 10.7451 -24 24v104h-160v-416zM276.687 195.303c10.0049 10.0049 27.3135 2.99707 27.3135 -11.3135v-111.976c0 -14.2939 -17.2959 -21.332 -27.3135 -11.3135l-52.6865 52.6738v-37.374
|
||||
c0 -11.0459 -8.9541 -20 -20 -20h-104c-11.0459 0 -20 8.9541 -20 20v104c0 11.0459 8.9541 20 20 20h104c11.0459 0 20 -8.9541 20 -20v-37.374z" />
|
||||
<glyph glyph-name="file-code" unicode="" horiz-adv-x="384"
|
||||
d="M149.9 98.9004c3.5 -3.30078 3.69922 -8.90039 0.399414 -12.4004l-17.3994 -18.5996c-1.60059 -1.80078 -4 -2.80078 -6.40039 -2.80078c-2.2002 0 -4.40039 0.900391 -6 2.40039l-57.7002 54.0996c-3.7002 3.40039 -3.7002 9.30078 0 12.8008l57.7002 54.0996
|
||||
c3.40039 3.2998 9 3.2002 12.4004 -0.400391l17.3994 -18.5996l0.200195 -0.200195c3.2002 -3.59961 2.7998 -9.2002 -0.799805 -12.3994l-32.7998 -28.9004l32.7998 -28.9004zM369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288
|
||||
c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM256 396.1v-76.0996h76.0996zM336 -16v288h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416h288zM209.6 234l24.4004 -7
|
||||
c4.7002 -1.2998 7.40039 -6.2002 6 -10.9004l-54.7002 -188.199c-1.2998 -4.60059 -6.2002 -7.40039 -10.8994 -6l-24.4004 7.09961c-4.7002 1.2998 -7.40039 6.2002 -6 10.9004l54.7002 188.1c1.39941 4.7002 6.2002 7.40039 10.8994 6zM234.1 157.1
|
||||
c-3.5 3.30078 -3.69922 8.90039 -0.399414 12.4004l17.3994 18.5996c3.30078 3.60059 8.90039 3.7002 12.4004 0.400391l57.7002 -54.0996c3.7002 -3.40039 3.7002 -9.30078 0 -12.8008l-57.7002 -54.0996c-3.5 -3.2998 -9.09961 -3.09961 -12.4004 0.400391
|
||||
l-17.3994 18.5996l-0.200195 0.200195c-3.2002 3.59961 -2.7998 9.2002 0.799805 12.3994l32.7998 28.9004l-32.7998 28.9004z" />
|
||||
<glyph glyph-name="life-ring" unicode=""
|
||||
d="M256 -56c-136.967 0 -248 111.033 -248 248s111.033 248 248 248s248 -111.033 248 -248s-111.033 -248 -248 -248zM152.602 20.7197c63.2178 -38.3184 143.579 -38.3184 206.797 0l-53.4111 53.4111c-31.8467 -13.5215 -68.168 -13.5059 -99.9746 0zM336 192
|
||||
c0 44.1123 -35.8877 80 -80 80s-80 -35.8877 -80 -80s35.8877 -80 80 -80s80 35.8877 80 80zM427.28 88.6016c38.3184 63.2178 38.3184 143.579 0 206.797l-53.4111 -53.4111c13.5215 -31.8467 13.5049 -68.168 0 -99.9746zM359.397 363.28
|
||||
c-63.2168 38.3184 -143.578 38.3184 -206.796 0l53.4111 -53.4111c31.8457 13.5215 68.167 13.5049 99.9736 0zM84.7197 295.398c-38.3184 -63.2178 -38.3184 -143.579 0 -206.797l53.4111 53.4111c-13.5215 31.8467 -13.5059 68.168 0 99.9746z" />
|
||||
<glyph glyph-name="paper-plane" unicode=""
|
||||
d="M440 441.5c34.5996 19.9004 77.5996 -8.7998 71.5 -48.9004l-59.4004 -387.199c-2.2998 -14.5 -11.0996 -27.3008 -23.8994 -34.5c-7.2998 -4.10059 -15.4004 -6.2002 -23.6006 -6.2002c-6.19922 0 -12.3994 1.2002 -18.2998 3.59961l-111.899 46.2002l-43.8008 -59.0996
|
||||
c-27.3994 -36.9004 -86.5996 -17.8008 -86.5996 28.5996v84.4004l-114.3 47.2998c-36.7998 15.0996 -40.1006 66 -5.7002 85.8994zM192 -16l36.5996 49.5l-36.5996 15.0996v-64.5996zM404.6 12.7002l59.4004 387.3l-416 -240l107.8 -44.5996l211.5 184.3
|
||||
c14.2002 12.2998 34.4004 -5.7002 23.7002 -21.2002l-140.2 -202.3z" />
|
||||
<glyph glyph-name="futbol" unicode="" horiz-adv-x="496"
|
||||
d="M483.8 268.6c42.2998 -130.199 -29 -270.1 -159.2 -312.399c-25.5 -8.2998 -51.2998 -12.2002 -76.6992 -12.2002c-104.5 0 -201.7 66.5996 -235.7 171.4c-42.2998 130.199 29 270.1 159.2 312.399c25.5 8.2998 51.2998 12.2002 76.6992 12.2002
|
||||
c104.5 0 201.7 -66.5996 235.7 -171.4zM409.3 74.9004c6.10059 8.39941 12.1006 16.8994 16.7998 26.1992c14.3008 28.1006 21.5 58.5 21.7002 89.2002l-38.8994 36.4004l-71.1006 -22.1006l-24.3994 -75.1992l43.6992 -60.9004zM409.3 310.3
|
||||
c-24.5 33.4004 -58.7002 58.4004 -97.8994 71.4004l-47.4004 -26.2002v-73.7998l64.2002 -46.5l70.7002 22zM184.9 381.6c-39.9004 -13.2998 -73.5 -38.5 -97.8008 -71.8994l10.1006 -52.5l70.5996 -22l64.2002 46.5v73.7998zM139 68.5l43.5 61.7002l-24.2998 74.2998
|
||||
l-71.1006 22.2002l-39 -36.4004c0.5 -55.7002 23.4004 -95.2002 37.8008 -115.3zM187.2 1.5c64.0996 -20.4004 115.5 -1.7998 121.7 0l22.3994 48.0996l-44.2998 61.7002h-78.5996l-43.6006 -61.7002z" />
|
||||
<glyph glyph-name="newspaper" unicode="" horiz-adv-x="576"
|
||||
d="M552 384c13.2549 0 24 -10.7451 24 -24v-336c0 -13.2549 -10.7451 -24 -24 -24h-496c-30.9277 0 -56 25.0723 -56 56v272c0 13.2549 10.7451 24 24 24h42.752c6.60547 18.623 24.3896 32 45.248 32h440zM48 56c0 -4.41113 3.58887 -8 8 -8s8 3.58887 8 8v248h-16v-248z
|
||||
M528 48v288h-416v-280c0 -2.7168 -0.204102 -5.38574 -0.578125 -8h416.578zM172 168c-6.62695 0 -12 5.37305 -12 12v96c0 6.62695 5.37305 12 12 12h136c6.62695 0 12 -5.37305 12 -12v-96c0 -6.62695 -5.37305 -12 -12 -12h-136zM200 248v-40h80v40h-80zM160 108v24
|
||||
c0 6.62695 5.37305 12 12 12h136c6.62695 0 12 -5.37305 12 -12v-24c0 -6.62695 -5.37305 -12 -12 -12h-136c-6.62695 0 -12 5.37305 -12 12zM352 108v24c0 6.62695 5.37305 12 12 12h104c6.62695 0 12 -5.37305 12 -12v-24c0 -6.62695 -5.37305 -12 -12 -12h-104
|
||||
c-6.62695 0 -12 5.37305 -12 12zM352 252v24c0 6.62695 5.37305 12 12 12h104c6.62695 0 12 -5.37305 12 -12v-24c0 -6.62695 -5.37305 -12 -12 -12h-104c-6.62695 0 -12 5.37305 -12 12zM352 180v24c0 6.62695 5.37305 12 12 12h104c6.62695 0 12 -5.37305 12 -12v-24
|
||||
c0 -6.62695 -5.37305 -12 -12 -12h-104c-6.62695 0 -12 5.37305 -12 12z" />
|
||||
<glyph glyph-name="bell-slash" unicode="" horiz-adv-x="640"
|
||||
d="M633.99 -23.0195c6.91016 -5.52051 8.01953 -15.5908 2.5 -22.4902l-10 -12.4902c-5.53027 -6.88965 -15.5898 -8.00977 -22.4902 -2.49023l-598 467.51c-6.90039 5.52051 -8.01953 15.5908 -2.49023 22.4902l10 12.4902
|
||||
c5.52051 6.90039 15.5898 8.00977 22.4902 2.49023zM163.53 80h182.84l61.3994 -48h-279.659c-19.1201 0 -31.9902 15.5996 -32.1006 32c-0.0498047 7.5498 2.61035 15.2598 8.61035 21.71c18.3701 19.7402 51.5703 49.6904 54.8398 140.42l45.4697 -35.5498
|
||||
c-6.91992 -54.7803 -24.6895 -88.5498 -41.3994 -110.58zM320 352c-23.3496 0 -45 -7.17969 -62.9404 -19.4004l-38.1699 29.8408c19.6807 15.7793 43.1104 27.3096 69.1299 32.7197v20.8398c0 17.6699 14.3203 32 31.9805 32s31.9805 -14.3301 31.9805 -32v-20.8398
|
||||
c73.46 -15.2598 127.939 -77.46 127.939 -155.16c0 -41.3604 6.03027 -70.7197 14.3398 -92.8496l-59.5293 46.54c-1.63086 13.96 -2.77051 28.8896 -2.79004 45.7295c0 0.200195 0.0595703 0.379883 0.0595703 0.580078c0 61.8604 -50.1396 112 -112 112zM320 -64
|
||||
c-35.3203 0 -63.9697 28.6504 -63.9697 64h127.939c0 -35.3496 -28.6494 -64 -63.9697 -64z" />
|
||||
<glyph glyph-name="copyright" unicode=""
|
||||
d="M256 440c136.967 0 248 -111.033 248 -248s-111.033 -248 -248 -248s-248 111.033 -248 248s111.033 248 248 248zM256 -8c110.549 0 200 89.4678 200 200c0 110.549 -89.4678 200 -200 200c-110.549 0 -200 -89.4688 -200 -200c0 -110.549 89.4678 -200 200 -200z
|
||||
M363.351 93.0645c-9.61328 -9.71289 -45.5293 -41.3965 -104.064 -41.3965c-82.4297 0 -140.484 61.4248 -140.484 141.567c0 79.1514 60.2754 139.4 139.763 139.4c55.5303 0 88.7373 -26.6201 97.5928 -34.7783c2.37793 -2.1875 3.86914 -5.3252 3.86914 -8.80762
|
||||
c0 -2.39746 -0.717773 -4.64258 -1.93359 -6.51465l-18.1543 -28.1133c-3.8418 -5.9502 -11.9668 -7.28223 -17.499 -2.9209c-8.5957 6.77637 -31.8145 22.5381 -61.708 22.5381c-48.3037 0 -77.916 -35.3301 -77.916 -80.082c0 -41.5889 26.8877 -83.6924 78.2764 -83.6924
|
||||
c32.6572 0 56.8428 19.0391 65.7266 27.2256c5.26953 4.85645 13.5957 4.03906 17.8193 -1.73828l19.8652 -27.1699c1.45996 -1.98145 2.32422 -4.42969 2.32422 -7.07715c0 -3.28809 -1.32422 -6.2793 -3.47656 -8.44043z" />
|
||||
<glyph glyph-name="closed-captioning" unicode=""
|
||||
d="M464 384c26.5 0 48 -21.5 48 -48v-288c0 -26.5 -21.5 -48 -48 -48h-416c-26.5 0 -48 21.5 -48 48v288c0 26.5 21.5 48 48 48h416zM458 48c3.2998 0 6 2.7002 6 6v276c0 3.2998 -2.7002 6 -6 6h-404c-3.2998 0 -6 -2.7002 -6 -6v-276c0 -3.2998 2.7002 -6 6 -6h404z
|
||||
M246.9 133.7c1.69922 -2.40039 1.5 -5.60059 -0.5 -7.7002c-53.6006 -56.7998 -172.801 -32.0996 -172.801 67.9004c0 97.2998 121.7 119.5 172.5 70.0996c2.10059 -2 2.5 -3.2002 1 -5.7002l-17.5 -30.5c-1.89941 -3.09961 -6.19922 -4 -9.09961 -1.7002
|
||||
c-40.7998 32 -94.5996 14.9004 -94.5996 -31.1992c0 -48 51 -70.5 92.1992 -32.6006c2.80078 2.5 7.10059 2.10059 9.2002 -0.899414zM437.3 133.7c1.7002 -2.40039 1.5 -5.60059 -0.5 -7.7002c-53.5996 -56.9004 -172.8 -32.0996 -172.8 67.9004
|
||||
c0 97.2998 121.7 119.5 172.5 70.0996c2.09961 -2 2.5 -3.2002 1 -5.7002l-17.5 -30.5c-1.90039 -3.09961 -6.2002 -4 -9.09961 -1.7002c-40.8008 32 -94.6006 14.9004 -94.6006 -31.1992c0 -48 51 -70.5 92.2002 -32.6006c2.7998 2.5 7.09961 2.10059 9.2002 -0.899414z
|
||||
" />
|
||||
<glyph glyph-name="object-group" unicode=""
|
||||
d="M500 320h-12v-256h12c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12h-72c-6.62695 0 -12 5.37305 -12 12v12h-320v-12c0 -6.62695 -5.37305 -12 -12 -12h-72c-6.62695 0 -12 5.37305 -12 12v72c0 6.62695 5.37305 12 12 12h12v256h-12
|
||||
c-6.62695 0 -12 5.37305 -12 12v72c0 6.62695 5.37305 12 12 12h72c6.62695 0 12 -5.37305 12 -12v-12h320v12c0 6.62695 5.37305 12 12 12h72c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12zM448 384v-32h32v32h-32zM32 384v-32h32v32h-32zM64 0v32
|
||||
h-32v-32h32zM480 0v32h-32v-32h32zM440 64v256h-12c-6.62695 0 -12 5.37305 -12 12v12h-320v-12c0 -6.62695 -5.37305 -12 -12 -12h-12v-256h12c6.62695 0 12 -5.37305 12 -12v-12h320v12c0 6.62695 5.37305 12 12 12h12zM404 256c6.62695 0 12 -5.37207 12 -12v-168
|
||||
c0 -6.62793 -5.37305 -12 -12 -12h-200c-6.62695 0 -12 5.37207 -12 12v52h-84c-6.62695 0 -12 5.37207 -12 12v168c0 6.62793 5.37305 12 12 12h200c6.62695 0 12 -5.37207 12 -12v-52h84zM136 280v-112h144v112h-144zM376 104v112h-56v-76
|
||||
c0 -6.62793 -5.37305 -12 -12 -12h-76v-24h144z" />
|
||||
<glyph glyph-name="object-ungroup" unicode="" horiz-adv-x="576"
|
||||
d="M564 224h-12v-160h12c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12h-72c-6.62695 0 -12 5.37305 -12 12v12h-224v-12c0 -6.62695 -5.37305 -12 -12 -12h-72c-6.62695 0 -12 5.37305 -12 12v72c0 6.62695 5.37305 12 12 12h12v24h-88v-12
|
||||
c0 -6.62695 -5.37305 -12 -12 -12h-72c-6.62695 0 -12 5.37305 -12 12v72c0 6.62695 5.37305 12 12 12h12v160h-12c-6.62695 0 -12 5.37305 -12 12v72c0 6.62695 5.37305 12 12 12h72c6.62695 0 12 -5.37305 12 -12v-12h224v12c0 6.62695 5.37305 12 12 12h72
|
||||
c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12h-12v-24h88v12c0 6.62695 5.37305 12 12 12h72c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12zM352 384v-32h32v32h-32zM352 128v-32h32v32h-32zM64 96v32h-32v-32h32zM64 352v32
|
||||
h-32v-32h32zM96 136h224v12c0 6.62695 5.37305 12 12 12h12v160h-12c-6.62695 0 -12 5.37305 -12 12v12h-224v-12c0 -6.62695 -5.37305 -12 -12 -12h-12v-160h12c6.62695 0 12 -5.37305 12 -12v-12zM224 0v32h-32v-32h32zM504 64v160h-12c-6.62695 0 -12 5.37305 -12 12v12
|
||||
h-88v-88h12c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12h-72c-6.62695 0 -12 5.37305 -12 12v12h-88v-24h12c6.62695 0 12 -5.37305 12 -12v-12h224v12c0 6.62695 5.37305 12 12 12h12zM544 0v32h-32v-32h32zM544 256v32h-32v-32h32z" />
|
||||
<glyph glyph-name="sticky-note" unicode="" horiz-adv-x="448"
|
||||
d="M448 99.8936c0 -13.2451 -5.37012 -25.252 -14.0586 -33.9404l-83.8828 -83.8818c-8.68848 -8.68848 -20.6943 -14.0596 -33.9404 -14.0596h-268.118c-26.5098 0 -48 21.4902 -48 48v351.988c0 26.5098 21.4902 48 48 48h352c26.5098 0 48 -21.4902 48 -48v-268.106z
|
||||
M320 19.8936l76.1182 76.1182h-76.1182v-76.1182zM400 368h-352v-351.988h224v104c0 13.2549 10.7451 24 24 24h104v223.988z" />
|
||||
<glyph glyph-name="clone" unicode=""
|
||||
d="M464 448c26.5098 0 48 -21.4902 48 -48v-320c0 -26.5098 -21.4902 -48 -48 -48h-48v-48c0 -26.5098 -21.4902 -48 -48 -48h-320c-26.5098 0 -48 21.4902 -48 48v320c0 26.5098 21.4902 48 48 48h48v48c0 26.5098 21.4902 48 48 48h320zM362 -16c3.31152 0 6 2.68848 6 6
|
||||
v42h-224c-26.5098 0 -48 21.4902 -48 48v224h-42c-3.31152 0 -6 -2.68848 -6 -6v-308c0 -3.31152 2.68848 -6 6 -6h308zM458 80c3.31152 0 6 2.68848 6 6v308c0 3.31152 -2.68848 6 -6 6h-308c-3.31152 0 -6 -2.68848 -6 -6v-308c0 -3.31152 2.68848 -6 6 -6h308z" />
|
||||
<glyph glyph-name="hourglass" unicode="" horiz-adv-x="384"
|
||||
d="M368 400c0 -80.0996 -31.8984 -165.619 -97.1797 -208c64.9912 -42.1934 97.1797 -127.436 97.1797 -208h4c6.62695 0 12 -5.37305 12 -12v-24c0 -6.62695 -5.37305 -12 -12 -12h-360c-6.62695 0 -12 5.37305 -12 12v24c0 6.62695 5.37305 12 12 12h4
|
||||
c0 80.0996 31.8994 165.619 97.1797 208c-64.9912 42.1934 -97.1797 127.436 -97.1797 208h-4c-6.62695 0 -12 5.37305 -12 12v24c0 6.62695 5.37305 12 12 12h360c6.62695 0 12 -5.37305 12 -12v-24c0 -6.62695 -5.37305 -12 -12 -12h-4zM64 400
|
||||
c0 -101.621 57.3066 -184 128 -184s128 82.3799 128 184h-256zM320 -16c0 101.62 -57.3076 184 -128 184s-128 -82.3799 -128 -184h256z" />
|
||||
<glyph glyph-name="hand-rock" unicode=""
|
||||
d="M408.864 368.948c48.8213 20.751 103.136 -15.0723 103.136 -67.9111v-114.443c0 -15.3955 -3.08887 -30.3906 -9.18262 -44.5674l-42.835 -99.6562c-4.99707 -11.625 -3.98242 -18.8574 -3.98242 -42.3701c0 -17.6729 -14.3271 -32 -32 -32h-252
|
||||
c-17.6729 0 -32 14.3271 -32 32c0 27.3301 1.1416 29.2012 -3.11035 32.9033l-97.71 85.0811c-24.8994 21.6797 -39.1797 52.8926 -39.1797 85.6338v56.9531c0 47.4277 44.8457 82.0215 91.0459 71.1807c1.96094 55.751 63.5107 87.8262 110.671 60.8057
|
||||
c29.1895 31.0713 78.8604 31.4473 108.334 -0.0214844c32.7051 18.6846 76.4121 10.3096 98.8135 -23.5879zM464 186.594v114.445c0 34.29 -52 33.8232 -52 0.676758c0 -8.83594 -7.16309 -16 -16 -16h-7c-8.83691 0 -16 7.16406 -16 16v26.751
|
||||
c0 34.457 -52 33.707 -52 0.676758v-27.4287c0 -8.83594 -7.16309 -16 -16 -16h-7c-8.83691 0 -16 7.16406 -16 16v40.4658c0 34.3525 -52 33.8115 -52 0.677734v-41.1436c0 -8.83594 -7.16406 -16 -16 -16h-7c-8.83594 0 -16 7.16406 -16 16v26.751
|
||||
c0 34.4023 -52 33.7744 -52 0.676758v-116.571c0 -8.83105 -7.17773 -15.9961 -16.0078 -15.9961c-4.0166 0 -7.68848 1.48242 -10.499 3.92969l-7 6.09473c-3.37012 2.93457 -5.49316 7.25293 -5.49316 12.0674v41.2275c0 34.2148 -52 33.8857 -52 0.677734v-56.9531
|
||||
c0 -18.8555 8.27441 -36.874 22.7002 -49.4365l97.71 -85.0801c12.4502 -10.8398 19.5898 -26.4463 19.5898 -42.8164v-10.2861h220v7.07617c0 13.21 2.65332 26.0791 7.88281 38.25l42.835 99.6553c3.37891 7.82715 5.28223 16.501 5.28223 25.5625v0.0498047z" />
|
||||
<glyph glyph-name="hand-paper" unicode="" horiz-adv-x="448"
|
||||
d="M372.57 335.359c39.9062 5.63281 75.4297 -25.7393 75.4297 -66.3594v-131.564c-0.00292969 -15.7393 -1.80566 -30.9482 -5.19531 -45.666l-30.1836 -130.958c-3.34668 -14.5234 -16.2783 -24.8125 -31.1816 -24.8125h-222.897
|
||||
c-10.7539 0 -20.2588 5.28613 -26.0615 13.4316l-119.97 168.415c-21.2441 29.8203 -14.8047 71.3574 14.5498 93.1533c18.7754 13.9395 42.1309 16.2979 62.083 8.87109v126.13c0 44.0547 41.125 75.5439 82.4053 64.9834c23.8926 48.1963 92.3535 50.2471 117.982 0.74707
|
||||
c42.5186 11.1445 83.0391 -21.9346 83.0391 -65.5469v-10.8242zM399.997 137.437l-0.00195312 131.563c0 24.9492 -36.5703 25.5508 -36.5703 -0.691406v-76.3086c0 -8.83691 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16309 -16 16v154.184
|
||||
c0 25.501 -36.5703 26.3633 -36.5703 0.691406v-154.875c0 -8.83691 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16309 -16 16v188.309c0 25.501 -36.5703 26.3545 -36.5703 0.691406v-189c0 -8.83691 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16309 -16 16
|
||||
v153.309c0 25.501 -36.5713 26.3359 -36.5713 0.691406v-206.494c0 -15.5703 -20.0352 -21.9092 -29.0303 -9.2832l-27.1279 38.0791c-14.3711 20.1709 -43.833 -2.33496 -29.3945 -22.6045l115.196 -161.697h201.92l27.3252 118.551
|
||||
c2.63086 11.417 3.96484 23.1553 3.96484 34.8857z" />
|
||||
<glyph glyph-name="hand-scissors" unicode=""
|
||||
d="M256 -32c-44.9561 0 -77.3428 43.2627 -64.0244 85.8535c-21.6484 13.71 -34.0156 38.7617 -30.3408 65.0068h-87.6348c-40.8037 0 -74 32.8105 -74 73.1406c0 40.3291 33.1963 73.1396 74 73.1396l94 -9.14062l-78.8496 18.6787
|
||||
c-38.3076 14.7422 -57.04 57.4707 -41.9424 95.1123c15.0303 37.4736 57.7549 55.7803 95.6416 41.2012l144.929 -55.7568c24.9551 30.5566 57.8086 43.9932 92.2178 24.7324l97.999 -54.8525c20.9746 -11.7393 34.0049 -33.8457 34.0049 -57.6904v-205.702
|
||||
c0 -30.7422 -21.4404 -57.5576 -51.7979 -64.5537l-118.999 -27.4268c-4.97168 -1.14648 -10.0889 -1.72949 -15.2031 -1.72949zM256 16.0127l70 -0.000976562c1.52441 0 2.99707 0.174805 4.42285 0.501953l119.001 27.4277
|
||||
c8.58203 1.97754 14.5762 9.29102 14.5762 17.7812v205.701c0 6.4873 -3.62109 12.542 -9.44922 15.8047l-98 54.8545c-8.13965 4.55566 -18.668 2.61914 -24.4873 -4.50781l-21.7646 -26.6475c-2.93457 -3.59375 -7.40332 -5.87305 -12.4004 -5.87305
|
||||
c-2.02246 0 -3.95703 0.375977 -5.73828 1.06152l-166.549 64.0908c-32.6543 12.5664 -50.7744 -34.5771 -19.2227 -46.7168l155.357 -59.7852c6 -2.30859 10.2539 -8.12402 10.2539 -14.9326v-11.6328c0 -8.83691 -7.16309 -16 -16 -16h-182
|
||||
c-34.375 0 -34.4297 -50.2803 0 -50.2803h182c8.83691 0 16 -7.16309 16 -16v-6.85645c0 -8.83691 -7.16309 -16 -16 -16h-28c-25.1221 0 -25.1592 -36.5674 0 -36.5674h28c8.83691 0 16 -7.16211 16 -16v-6.85547c0 -8.83691 -7.16309 -16 -16 -16
|
||||
c-25.1201 0 -25.1602 -36.5674 0 -36.5674z" />
|
||||
<glyph glyph-name="hand-lizard" unicode="" horiz-adv-x="576"
|
||||
d="M556.686 157.458c12.6357 -19.4863 19.3145 -42.0615 19.3145 -65.2871v-124.171h-224v71.582l-99.751 38.7871c-2.7832 1.08203 -5.70996 1.63086 -8.69727 1.63086h-131.552c-30.8789 0 -56 25.1211 -56 56c0 48.5234 39.4766 88 88 88h113.709l18.333 48h-196.042
|
||||
c-44.1123 0 -80 35.8877 -80 80v8c0 30.8779 25.1211 56 56 56h293.917c24.5 0 47.084 -12.2725 60.4111 -32.8291zM528 16v76.1709c0 0.0166016 -0.0439453 0.106445 -0.0439453 0.12207c0 14.3945 -4.24219 27.8057 -11.5439 39.0498l-146.358 225.715
|
||||
c-4.44336 6.85254 -11.9707 10.9424 -20.1367 10.9424h-293.917c-4.41113 0 -8 -3.58887 -8 -8v-8c0 -17.6445 14.3555 -32 32 -32h213.471c25.2021 0 42.626 -25.293 33.6299 -48.8457l-24.5518 -64.2812c-7.05371 -18.4658 -25.0732 -30.873 -44.8398 -30.873h-113.709
|
||||
c-22.0557 0 -40 -17.9443 -40 -40c0 -4.41113 3.58887 -8 8 -8h131.552c0.0175781 0 0.0712891 -0.0273438 0.0888672 -0.0273438c9.16992 0 17.9404 -1.72461 26.0039 -4.86621l99.752 -38.7881c18.5898 -7.22852 30.6035 -24.7881 30.6035 -44.7363v-23.582h128z" />
|
||||
<glyph glyph-name="hand-spock" unicode=""
|
||||
d="M501.03 331.824c6.92773 -11.1826 10.9697 -24.4053 10.9697 -38.5146c0 -5.92676 -0.706055 -11.6885 -2.03809 -17.208l-57.623 -241.963c-13.2236 -56.1904 -63.707 -98.1387 -123.908 -98.1387h-0.352539h-107.455
|
||||
c-0.0761719 0 -0.193359 0.00195312 -0.270508 0.00195312c-40.9248 0 -78.1475 15.9814 -105.761 42.0391l-91.3652 85.9766c-14.3076 13.4434 -23.2246 32.5547 -23.2246 53.7168c0 19.5254 7.61035 37.2861 20.0254 50.4766
|
||||
c5.31836 5.66406 29.875 29.3926 68.1152 21.8477l-24.3594 82.1973c-1.97363 6.64844 -2.97656 13.6836 -2.97656 20.9688c0 38.6953 29.8926 70.4639 67.8262 73.4531c-0.246094 2.45117 -0.34082 4.85547 -0.34082 7.37207c0 34.4199 23.585 63.376 55.4619 71.5752
|
||||
c43.248 10.9785 80.5645 -17.7012 89.6602 -53.0723l13.6836 -53.207l4.64648 22.6602c6.99023 33.5186 36.6826 58.8037 72.2373 58.916c8.73438 0 56.625 -3.26953 70.7383 -54.0801c15.0664 0.710938 46.9199 -3.50977 66.3105 -35.0176zM463.271 287.219
|
||||
c7.86914 32.9844 -42.1211 45.2695 -50.0859 11.9219l-24.8008 -104.146c-4.38867 -18.4141 -31.7783 -11.8926 -28.0557 6.2168l28.5479 139.166c7.39844 36.0703 -43.3076 45.0703 -50.1182 11.9629l-31.791 -154.971
|
||||
c-3.54883 -17.3086 -28.2832 -18.0469 -32.7109 -0.804688l-47.3262 184.035c-8.43359 32.8105 -58.3691 20.2676 -49.8652 -12.8359l42.4414 -165.039c4.81641 -18.7207 -23.3711 -26.9121 -28.9648 -8.00781l-31.3438 105.779
|
||||
c-9.6875 32.6465 -59.1191 18.2578 -49.3867 -14.625l36.0137 -121.539c6.59375 -22.2441 10.1777 -45.7803 10.1777 -70.1523c0 -6.54297 -8.05664 -10.9355 -13.4824 -5.82617l-51.123 48.1074c-24.7852 23.4082 -60.0527 -14.1875 -35.2793 -37.4902l91.3691 -85.9805
|
||||
c19.0469 -17.9736 44.75 -28.998 72.9795 -28.998h0.157227h107.455c0.0732422 0 0.138672 0.0429688 0.212891 0.0429688c37.5791 0 69.1016 26.1416 77.3564 61.2168z" />
|
||||
<glyph glyph-name="hand-pointer" unicode="" horiz-adv-x="448"
|
||||
d="M358.182 268.639c43.1934 16.6348 89.8184 -15.7949 89.8184 -62.6387v-84c-0.000976562 -5.24023 -0.600586 -10.3037 -1.72754 -15.2041l-27.4297 -118.999c-6.98242 -30.2969 -33.7549 -51.7969 -64.5566 -51.7969h-178.286
|
||||
c-21.2588 0 -41.3682 10.4102 -53.791 27.8457l-109.699 154.001c-21.2432 29.8193 -14.8047 71.3574 14.5498 93.1523c18.8115 13.9658 42.1748 16.2822 62.083 8.87207v161.129c0 36.9443 29.7363 67 66.2861 67s66.2861 -30.0557 66.2861 -67v-73.6338
|
||||
c20.4131 2.85742 41.4678 -3.94238 56.5947 -19.6289c27.1934 12.8467 60.3799 5.66992 79.8721 -19.0986zM80.9854 168.303c-14.4004 20.2119 -43.8008 -2.38281 -29.3945 -22.6055l109.712 -154c3.43457 -4.81934 8.92871 -7.69727 14.6973 -7.69727h178.285
|
||||
c8.49219 0 15.8037 5.99414 17.7822 14.5762l27.4297 119.001c0.333008 1.44629 0.501953 2.93457 0.501953 4.42285v84c0 25.1602 -36.5713 25.1211 -36.5713 0c0 -8.83594 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16406 -16 16v21
|
||||
c0 25.1602 -36.5713 25.1201 -36.5713 0v-21c0 -8.83594 -7.16309 -16 -16 -16h-6.85938c-8.83691 0 -16 7.16406 -16 16v35c0 25.1602 -36.5703 25.1201 -36.5703 0v-35c0 -8.83594 -7.16309 -16 -16 -16h-6.85742c-8.83691 0 -16 7.16406 -16 16v175
|
||||
c0 25.1602 -36.5713 25.1201 -36.5713 0v-241.493c0 -15.5703 -20.0352 -21.9092 -29.0303 -9.2832zM176.143 48v96c0 8.83691 6.26855 16 14 16h6c7.73242 0 14 -7.16309 14 -16v-96c0 -8.83691 -6.26758 -16 -14 -16h-6c-7.73242 0 -14 7.16309 -14 16zM251.571 48v96
|
||||
c0 8.83691 6.26758 16 14 16h6c7.73145 0 14 -7.16309 14 -16v-96c0 -8.83691 -6.26855 -16 -14 -16h-6c-7.73242 0 -14 7.16309 -14 16zM327 48v96c0 8.83691 6.26758 16 14 16h6c7.73242 0 14 -7.16309 14 -16v-96c0 -8.83691 -6.26758 -16 -14 -16h-6
|
||||
c-7.73242 0 -14 7.16309 -14 16z" />
|
||||
<glyph glyph-name="hand-peace" unicode="" horiz-adv-x="448"
|
||||
d="M362.146 256.024c42.5908 13.3184 85.8535 -19.0684 85.8535 -64.0244l-0.0117188 -70.001c-0.000976562 -5.24023 -0.600586 -10.3027 -1.72949 -15.2031l-27.4268 -118.999c-6.99707 -30.3564 -33.8105 -51.7969 -64.5547 -51.7969h-205.702
|
||||
c-23.8447 0 -45.9502 13.0303 -57.6904 34.0059l-54.8525 97.999c-19.2607 34.4092 -5.82422 67.2617 24.7324 92.2178l-55.7568 144.928c-14.5791 37.8867 3.72754 80.6113 41.2012 95.6416c37.6406 15.0977 80.3691 -3.63477 95.1123 -41.9424l18.6787 -78.8496
|
||||
l-9.14062 94c0 40.8037 32.8096 74 73.1396 74s73.1406 -33.1963 73.1406 -74v-87.6348c26.2451 3.6748 51.2959 -8.69238 65.0068 -30.3408zM399.987 122l-0.000976562 70c0 25.1602 -36.5674 25.1201 -36.5674 0c0 -8.83691 -7.16309 -16 -16 -16h-6.85547
|
||||
c-8.83789 0 -16 7.16309 -16 16v28c0 25.1592 -36.5674 25.1221 -36.5674 0v-28c0 -8.83691 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16309 -16 16v182c0 34.4297 -50.2803 34.375 -50.2803 0v-182c0 -8.83691 -7.16309 -16 -16 -16h-11.6328
|
||||
c-6.80859 0 -12.624 4.25391 -14.9326 10.2539l-59.7842 155.357c-12.1396 31.5518 -59.2842 13.4326 -46.7168 -19.2227l64.0898 -166.549c0.685547 -1.78125 1.07812 -3.71875 1.07812 -5.74121c0 -4.99707 -2.2959 -9.46289 -5.88965 -12.3975l-26.6475 -21.7646
|
||||
c-7.12695 -5.81934 -9.06445 -16.3467 -4.50781 -24.4873l54.8535 -98c3.26367 -5.82812 9.31934 -9.44922 15.8057 -9.44922h205.701c8.49121 0 15.8037 5.99414 17.7812 14.5762l27.4277 119.001c0.333008 1.44629 0.501953 2.93457 0.501953 4.42285z" />
|
||||
<glyph glyph-name="registered" unicode=""
|
||||
d="M256 440c136.967 0 248 -111.033 248 -248s-111.033 -248 -248 -248s-248 111.033 -248 248s111.033 248 248 248zM256 -8c110.549 0 200 89.4678 200 200c0 110.549 -89.4678 200 -200 200c-110.549 0 -200 -89.4688 -200 -200c0 -110.549 89.4678 -200 200 -200z
|
||||
M366.442 73.791c4.40332 -7.99219 -1.37012 -17.791 -10.5107 -17.791h-42.8096c-0.00488281 0 -0.000976562 -0.0126953 -0.00585938 -0.0126953c-4.58594 0 -8.57422 2.58301 -10.5869 6.37305l-47.5156 89.3027h-31.958v-83.6631c0 -6.61719 -5.38281 -12 -12 -12
|
||||
h-38.5674c-6.61719 0 -12 5.38281 -12 12v248.304c0 6.61719 5.38281 12 12 12h78.667c71.251 0 101.498 -32.749 101.498 -85.252c0 -31.6123 -15.2148 -59.2969 -39.4824 -73.1758c3.02148 -4.61719 0.225586 0.199219 53.2715 -96.085zM256.933 208.094
|
||||
c20.9131 0 32.4307 11.5186 32.4316 32.4316c0 19.5752 -6.5127 31.709 -38.9297 31.709h-27.377v-64.1406h33.875z" />
|
||||
<glyph glyph-name="calendar-plus" unicode="" horiz-adv-x="448"
|
||||
d="M336 156v-24c0 -6.59961 -5.40039 -12 -12 -12h-76v-76c0 -6.59961 -5.40039 -12 -12 -12h-24c-6.59961 0 -12 5.40039 -12 12v76h-76c-6.59961 0 -12 5.40039 -12 12v24c0 6.59961 5.40039 12 12 12h76v76c0 6.59961 5.40039 12 12 12h24c6.59961 0 12 -5.40039 12 -12
|
||||
v-76h76c6.59961 0 12 -5.40039 12 -12zM448 336v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h48v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h128v52c0 6.59961 5.40039 12 12 12h40
|
||||
c6.59961 0 12 -5.40039 12 -12v-52h48c26.5 0 48 -21.5 48 -48zM400 -10v298h-352v-298c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
||||
<glyph glyph-name="calendar-minus" unicode="" horiz-adv-x="448"
|
||||
d="M124 120c-6.59961 0 -12 5.40039 -12 12v24c0 6.59961 5.40039 12 12 12h200c6.59961 0 12 -5.40039 12 -12v-24c0 -6.59961 -5.40039 -12 -12 -12h-200zM448 336v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h48v52
|
||||
c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h128v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h48c26.5 0 48 -21.5 48 -48zM400 -10v298h-352v-298c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
||||
<glyph glyph-name="calendar-times" unicode="" horiz-adv-x="448"
|
||||
d="M311.7 73.2998l-17 -17c-4.7002 -4.7002 -12.2998 -4.7002 -17 0l-53.7002 53.7998l-53.7002 -53.6992c-4.7002 -4.7002 -12.2998 -4.7002 -17 0l-17 17c-4.7002 4.69922 -4.7002 12.2998 0 17l53.7002 53.6992l-53.7002 53.7002c-4.7002 4.7002 -4.7002 12.2998 0 17
|
||||
l17 17c4.7002 4.7002 12.2998 4.7002 17 0l53.7002 -53.7002l53.7002 53.7002c4.7002 4.7002 12.2998 4.7002 17 0l17 -17c4.7002 -4.7002 4.7002 -12.2998 0 -17l-53.7998 -53.7998l53.6992 -53.7002c4.80078 -4.7002 4.80078 -12.2998 0.100586 -17zM448 336v-352
|
||||
c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h48v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h128v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h48c26.5 0 48 -21.5 48 -48zM400 -10
|
||||
v298h-352v-298c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
||||
<glyph glyph-name="calendar-check" unicode="" horiz-adv-x="448"
|
||||
d="M400 384c26.5098 0 48 -21.4902 48 -48v-352c0 -26.5098 -21.4902 -48 -48 -48h-352c-26.5098 0 -48 21.4902 -48 48v352c0 26.5098 21.4902 48 48 48h48v52c0 6.62695 5.37305 12 12 12h40c6.62695 0 12 -5.37305 12 -12v-52h128v52c0 6.62695 5.37305 12 12 12h40
|
||||
c6.62695 0 12 -5.37305 12 -12v-52h48zM394 -16c3.31152 0 6 2.68848 6 6v298h-352v-298c0 -3.31152 2.68848 -6 6 -6h340zM341.151 184.65l-142.31 -141.169c-4.70508 -4.66699 -12.3027 -4.6377 -16.9707 0.0673828l-75.0908 75.6992
|
||||
c-4.66699 4.70508 -4.6377 12.3027 0.0673828 16.9707l22.7197 22.5361c4.70508 4.66699 12.3027 4.63672 16.9697 -0.0693359l44.1035 -44.4609l111.072 110.182c4.70508 4.66699 12.3027 4.63672 16.9707 -0.0683594l22.5361 -22.7178
|
||||
c4.66699 -4.70508 4.63672 -12.3027 -0.0683594 -16.9697z" />
|
||||
<glyph glyph-name="map" unicode="" horiz-adv-x="576"
|
||||
d="M560.02 416c8.4502 0 15.9805 -6.83008 15.9805 -16.0195v-346.32c0 -13.4707 -8.32422 -24.9951 -20.1201 -29.71l-151.83 -52.8105c-6.23242 -2.02832 -12.9023 -3.12305 -19.8076 -3.12305c-7.07324 0 -13.8799 1.15039 -20.2422 3.27344l-172 60.71l-170.05 -62.8398
|
||||
c-1.99023 -0.790039 -4 -1.16016 -5.95996 -1.16016c-8.45996 0 -15.9902 6.83008 -15.9902 16.0195v346.32c0.00292969 13.4697 8.32617 24.9932 20.1201 29.71l151.83 52.8105c6.43945 2.08984 13.1201 3.13965 19.8096 3.13965
|
||||
c7.06641 -0.00292969 13.8789 -1.16602 20.2402 -3.28027l172 -60.7197h0.00976562l170.05 62.8398c1.98047 0.790039 4 1.16016 5.95996 1.16016zM224 357.58v-285.97l128 -45.1904v285.97zM48 29.9502l127.36 47.0801l0.639648 0.229492v286.2l-128 -44.5303v-288.979z
|
||||
M528 65.0801v288.97l-127.36 -47.0693l-0.639648 -0.240234v-286.19z" />
|
||||
<glyph glyph-name="comment-alt" unicode=""
|
||||
d="M448 448c35.2998 0 64 -28.7002 64 -64v-288c0 -35.2998 -28.7002 -64 -64 -64h-144l-124.9 -93.5996c-2.19922 -1.7002 -4.69922 -2.40039 -7.09961 -2.40039c-6.2002 0 -12 4.90039 -12 12v84h-96c-35.2998 0 -64 28.7002 -64 64v288c0 35.2998 28.7002 64 64 64h384z
|
||||
M464 96v288c0 8.7998 -7.2002 16 -16 16h-384c-8.7998 0 -16 -7.2002 -16 -16v-288c0 -8.7998 7.2002 -16 16 -16h144v-60l67.2002 50.4004l12.7998 9.59961h160c8.7998 0 16 7.2002 16 16z" />
|
||||
<glyph glyph-name="pause-circle" unicode=""
|
||||
d="M256 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM256 -8c110.5 0 200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200s89.5 -200 200 -200zM352 272v-160c0 -8.7998 -7.2002 -16 -16 -16h-48
|
||||
c-8.7998 0 -16 7.2002 -16 16v160c0 8.7998 7.2002 16 16 16h48c8.7998 0 16 -7.2002 16 -16zM240 272v-160c0 -8.7998 -7.2002 -16 -16 -16h-48c-8.7998 0 -16 7.2002 -16 16v160c0 8.7998 7.2002 16 16 16h48c8.7998 0 16 -7.2002 16 -16z" />
|
||||
<glyph glyph-name="stop-circle" unicode=""
|
||||
d="M504 192c0 -137 -111 -248 -248 -248s-248 111 -248 248s111 248 248 248s248 -111 248 -248zM56 192c0 -110.5 89.5 -200 200 -200s200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200zM352 272v-160c0 -8.7998 -7.2002 -16 -16 -16h-160
|
||||
c-8.7998 0 -16 7.2002 -16 16v160c0 8.7998 7.2002 16 16 16h160c8.7998 0 16 -7.2002 16 -16z" />
|
||||
<glyph glyph-name="handshake" unicode="" horiz-adv-x="640"
|
||||
d="M519.2 320.1h120.8v-255.699h-64c-17.5 0 -31.7998 14.1992 -31.9004 31.6992h-57.8994c-1.7998 -8.19922 -5.2998 -16.0996 -10.9004 -23l-26.2002 -32.2998c-15.7998 -19.3994 -41.8994 -25.5 -64 -16.7998c-13.5 -16.5996 -30.5996 -24 -48.7998 -24
|
||||
c-15.0996 0 -28.5996 5.09961 -41.0996 15.9004c-31.7998 -21.9004 -74.7002 -21.3008 -105.601 3.7998l-84.5996 76.3994h-9.09961c-0.100586 -17.5 -14.3008 -31.6992 -31.9004 -31.6992h-64v255.699h118l47.5996 47.6006c10.5 10.3994 24.8008 16.2998 39.6006 16.2998
|
||||
h226.8c15.4326 0 29.4326 -6.22168 39.5996 -16.2998zM48 96.4004c8.7998 0 16 7.09961 16 16c0 8.7998 -7.2002 16 -16 16s-16 -7.2002 -16 -16c0 -8.80078 7.2002 -16 16 -16zM438 103.3c2.7002 3.40039 2.2002 8.5 -1.2002 11.2998l-108.2 87.8008l-8.19922 -7.5
|
||||
c-40.3008 -36.8008 -86.7002 -11.8008 -101.5 4.39941c-26.7002 29 -25 74.4004 4.39941 101.3l38.7002 35.5h-56.7002c-2 -0.799805 -3.7002 -1.5 -5.7002 -2.2998l-61.6992 -61.5996h-41.9004v-128.101h27.7002l97.2998 -88
|
||||
c16.0996 -13.0996 41.4004 -10.5 55.2998 6.60059l15.6006 19.2002l36.7998 -31.5c3 -2.40039 12 -4.90039 18 2.39941l30 36.5l23.8994 -19.3994c3.5 -2.80078 8.5 -2.2002 11.3008 1.19922zM544 144.1v128h-44.7002l-61.7002 61.6006
|
||||
c-1.39941 1.5 -3.39941 2.2998 -5.5 2.2998l-83.6992 -0.200195c-10 0 -19.6006 -3.7002 -27 -10.5l-65.6006 -60.0996c-9.7002 -8.7998 -10.5 -24 -1.2002 -33.9004c8.90039 -9.39941 25.1006 -8.7002 34.6006 0l55.2002 50.6006c6.5 5.89941 16.5996 5.5 22.5996 -1
|
||||
l10.9004 -11.7002c6 -6.5 5.5 -16.6006 -1 -22.6006l-12.5 -11.3994l102.699 -83.4004c2.80078 -2.2998 5.40039 -4.89941 7.7002 -7.7002h69.2002zM592 96.4004c8.7998 0 16 7.09961 16 16c0 8.7998 -7.2002 16 -16 16s-16 -7.2002 -16 -16c0 -8.80078 7.2002 -16 16 -16z
|
||||
" />
|
||||
<glyph glyph-name="envelope-open" unicode=""
|
||||
d="M494.586 283.484c10.6523 -8.80762 17.4141 -22.1064 17.4141 -36.9932v-262.491c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v262.515c0 14.9355 6.80469 28.2705 17.5146 37.0771c4.08008 3.35449 110.688 89.0996 135.15 108.549
|
||||
c22.6992 18.1426 60.1299 55.8594 103.335 55.8594c43.4365 0 81.2314 -38.1914 103.335 -55.8594c23.5283 -18.707 130.554 -104.773 135.251 -108.656zM464 -10v253.632c0 0.00195312 0.00390625 0.000976562 0.00390625 0.00292969
|
||||
c0 1.88184 -0.869141 3.56152 -2.22754 4.66016c-15.8633 12.8232 -108.793 87.5752 -132.366 106.316c-17.5527 14.0195 -49.7168 45.3887 -73.4102 45.3887c-23.6016 0 -55.2451 -30.8799 -73.4102 -45.3887c-23.5713 -18.7393 -116.494 -93.4795 -132.364 -106.293
|
||||
c-1.40918 -1.13965 -2.22559 -2.85254 -2.22559 -4.66504v-253.653c0 -3.31152 2.68848 -6 6 -6h404c3.31152 0 6 2.68848 6 6zM432.009 177.704c4.24902 -5.15918 3.46484 -12.7949 -1.74512 -16.9814c-28.9746 -23.2822 -59.2734 -47.5967 -70.9287 -56.8623
|
||||
c-22.6992 -18.1436 -60.1299 -55.8604 -103.335 -55.8604c-43.4521 0 -81.2871 38.2373 -103.335 55.8604c-11.2793 8.9668 -41.7441 33.4131 -70.9268 56.8643c-5.20996 4.1875 -5.99316 11.8223 -1.74512 16.9814l15.2578 18.5283
|
||||
c4.17773 5.07227 11.6572 5.84277 16.7793 1.72559c28.6182 -23.001 58.5654 -47.0352 70.5596 -56.5713c17.5527 -14.0195 49.7168 -45.3887 73.4102 -45.3887c23.6016 0 55.2461 30.8799 73.4102 45.3887c11.9941 9.53516 41.9434 33.5703 70.5625 56.5684
|
||||
c5.12207 4.11621 12.6016 3.3457 16.7783 -1.72656z" />
|
||||
<glyph glyph-name="address-book" unicode="" horiz-adv-x="448"
|
||||
d="M436 288h-20v-64h20c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12h-20v-64h20c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12h-20v-48c0 -26.5 -21.5 -48 -48 -48h-320c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48
|
||||
h320c26.5 0 48 -21.5 48 -48v-48h20c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12zM368 -16v416h-320v-416h320zM208 192c-35.2998 0 -64 28.7002 -64 64s28.7002 64 64 64s64 -28.7002 64 -64s-28.7002 -64 -64 -64zM118.4 64
|
||||
c-12.4004 0 -22.4004 8.59961 -22.4004 19.2002v19.2002c0 31.7998 30.0996 57.5996 67.2002 57.5996c11.3994 0 17.8994 -8 44.7998 -8c26.0996 0 34 8 44.7998 8c37.1006 0 67.2002 -25.7998 67.2002 -57.5996v-19.2002c0 -10.6006 -10 -19.2002 -22.4004 -19.2002
|
||||
h-179.199z" />
|
||||
<glyph glyph-name="address-card" unicode="" horiz-adv-x="576"
|
||||
d="M528 416c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-480c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h480zM528 16v352h-480v-352h480zM208 192c-35.2998 0 -64 28.7002 -64 64s28.7002 64 64 64s64 -28.7002 64 -64s-28.7002 -64 -64 -64z
|
||||
M118.4 64c-12.4004 0 -22.4004 8.59961 -22.4004 19.2002v19.2002c0 31.7998 30.0996 57.5996 67.2002 57.5996c11.3994 0 17.8994 -8 44.7998 -8c26.0996 0 34 8 44.7998 8c37.1006 0 67.2002 -25.7998 67.2002 -57.5996v-19.2002
|
||||
c0 -10.6006 -10 -19.2002 -22.4004 -19.2002h-179.199zM360 128c-4.40039 0 -8 3.59961 -8 8v16c0 4.40039 3.59961 8 8 8h112c4.40039 0 8 -3.59961 8 -8v-16c0 -4.40039 -3.59961 -8 -8 -8h-112zM360 192c-4.40039 0 -8 3.59961 -8 8v16c0 4.40039 3.59961 8 8 8h112
|
||||
c4.40039 0 8 -3.59961 8 -8v-16c0 -4.40039 -3.59961 -8 -8 -8h-112zM360 256c-4.40039 0 -8 3.59961 -8 8v16c0 4.40039 3.59961 8 8 8h112c4.40039 0 8 -3.59961 8 -8v-16c0 -4.40039 -3.59961 -8 -8 -8h-112z" />
|
||||
<glyph glyph-name="user-circle" unicode="" horiz-adv-x="496"
|
||||
d="M248 344c53 0 96 -43 96 -96s-43 -96 -96 -96s-96 43 -96 96s43 96 96 96zM248 200c26.5 0 48 21.5 48 48s-21.5 48 -48 48s-48 -21.5 -48 -48s21.5 -48 48 -48zM248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8
|
||||
c49.7002 0 95.0996 18.2998 130.1 48.4004c-14.8994 23 -40.3994 38.5 -69.5996 39.5c-20.7998 -6.5 -40.5996 -9.60059 -60.5 -9.60059s-39.7002 3.2002 -60.5 9.60059c-29.2002 -0.900391 -54.7002 -16.5 -69.5996 -39.5c35 -30.1006 80.3994 -48.4004 130.1 -48.4004z
|
||||
M410.7 76.0996c23.3994 32.7002 37.2998 72.7002 37.2998 115.9c0 110.3 -89.7002 200 -200 200s-200 -89.7002 -200 -200c0 -43.2002 13.9004 -83.2002 37.2998 -115.9c24.5 31.4004 62.2002 51.9004 105.101 51.9004c10.1992 0 26.0996 -9.59961 57.5996 -9.59961
|
||||
c31.5996 0 47.4004 9.59961 57.5996 9.59961c43 0 80.7002 -20.5 105.101 -51.9004z" />
|
||||
<glyph glyph-name="id-badge" unicode="" horiz-adv-x="384"
|
||||
d="M336 448c26.5 0 48 -21.5 48 -48v-416c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48h288zM336 -16v416h-288v-416h288zM144 336c-8.7998 0 -16 7.2002 -16 16s7.2002 16 16 16h96c8.7998 0 16 -7.2002 16 -16s-7.2002 -16 -16 -16
|
||||
h-96zM192 160c-35.2998 0 -64 28.7002 -64 64s28.7002 64 64 64s64 -28.7002 64 -64s-28.7002 -64 -64 -64zM102.4 32c-12.4004 0 -22.4004 8.59961 -22.4004 19.2002v19.2002c0 31.7998 30.0996 57.5996 67.2002 57.5996c11.3994 0 17.8994 -8 44.7998 -8
|
||||
c26.0996 0 34 8 44.7998 8c37.1006 0 67.2002 -25.7998 67.2002 -57.5996v-19.2002c0 -10.6006 -10 -19.2002 -22.4004 -19.2002h-179.199z" />
|
||||
<glyph glyph-name="id-card" unicode="" horiz-adv-x="576"
|
||||
d="M528 416c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-480c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h480zM528 16v288h-480v-288h32.7998c-1 4.5 -0.799805 -3.59961 -0.799805 22.4004c0 31.7998 30.0996 57.5996 67.2002 57.5996
|
||||
c11.3994 0 17.8994 -8 44.7998 -8c26.0996 0 34 8 44.7998 8c37.1006 0 67.2002 -25.7998 67.2002 -57.5996c0 -26 0.0996094 -17.9004 -0.799805 -22.4004h224.8zM360 96c-4.40039 0 -8 3.59961 -8 8v16c0 4.40039 3.59961 8 8 8h112c4.40039 0 8 -3.59961 8 -8v-16
|
||||
c0 -4.40039 -3.59961 -8 -8 -8h-112zM360 160c-4.40039 0 -8 3.59961 -8 8v16c0 4.40039 3.59961 8 8 8h112c4.40039 0 8 -3.59961 8 -8v-16c0 -4.40039 -3.59961 -8 -8 -8h-112zM360 224c-4.40039 0 -8 3.59961 -8 8v16c0 4.40039 3.59961 8 8 8h112
|
||||
c4.40039 0 8 -3.59961 8 -8v-16c0 -4.40039 -3.59961 -8 -8 -8h-112zM192 128c-35.2998 0 -64 28.7002 -64 64s28.7002 64 64 64s64 -28.7002 64 -64s-28.7002 -64 -64 -64z" />
|
||||
<glyph glyph-name="window-maximize" unicode=""
|
||||
d="M464 416c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-416c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h416zM464 22v234h-416v-234c0 -3.2998 2.7002 -6 6 -6h404c3.2998 0 6 2.7002 6 6z" />
|
||||
<glyph glyph-name="window-minimize" unicode=""
|
||||
d="M480 -32h-448c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32h448c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32z" />
|
||||
<glyph glyph-name="window-restore" unicode=""
|
||||
d="M464 448c26.5 0 48 -21.5 48 -48v-320c0 -26.5 -21.5 -48 -48 -48h-48v-48c0 -26.5 -21.5 -48 -48 -48h-320c-26.5 0 -48 21.5 -48 48v320c0 26.5 21.5 48 48 48h48v48c0 26.5 21.5 48 48 48h320zM368 -16v208h-320v-208h320zM464 80v320h-320v-48h224
|
||||
c26.5 0 48 -21.5 48 -48v-224h48z" />
|
||||
<glyph glyph-name="snowflake" unicode="" horiz-adv-x="448"
|
||||
d="M440.1 92.7998c7.60059 -4.39941 10.1006 -14.2002 5.5 -21.7002l-7.89941 -13.8994c-4.40039 -7.7002 -14 -10.2998 -21.5 -5.90039l-39.2002 23l9.09961 -34.7002c2.30078 -8.5 -2.69922 -17.2998 -11.0996 -19.5996l-15.2002 -4.09961
|
||||
c-8.39941 -2.30078 -17.0996 2.7998 -19.2998 11.2998l-21.2998 81l-71.9004 42.2002v-84.5l58.2998 -59.3008c6.10059 -6.19922 6.10059 -16.3994 0 -22.5996l-11.0996 -11.2998c-6.09961 -6.2002 -16.0996 -6.2002 -22.2002 0l-24.8994 25.3994v-46.0996
|
||||
c0 -8.7998 -7 -16 -15.7002 -16h-15.7002c-8.7002 0 -15.7002 7.2002 -15.7002 16v45.9004l-24.8994 -25.4004c-6.10059 -6.2002 -16.1006 -6.2002 -22.2002 0l-11.1006 11.2998c-6.09961 6.2002 -6.09961 16.4004 0 22.6006l58.3008 59.2998v84.5l-71.9004 -42.2002
|
||||
l-21.2998 -81c-2.2998 -8.5 -10.9004 -13.5996 -19.2998 -11.2998l-15.2002 4.09961c-8.40039 2.2998 -13.2998 11.1006 -11.1006 19.6006l9.10059 34.6992l-39.2002 -23c-7.5 -4.39941 -17.2002 -1.7998 -21.5 5.90039l-7.90039 13.9004
|
||||
c-4.2998 7.69922 -1.69922 17.5 5.80078 21.8994l39.1992 23l-34.0996 9.2998c-8.40039 2.30078 -13.2998 11.1006 -11.0996 19.6006l4.09961 15.5c2.2998 8.5 10.9004 13.5996 19.2998 11.2998l79.7002 -21.7002l71.9004 42.2002l-71.9004 42.2002l-79.7002 -21.7002
|
||||
c-8.39941 -2.2998 -17.0996 2.7998 -19.2998 11.2998l-4.09961 15.5c-2.30078 8.5 2.69922 17.2998 11.0996 19.6006l34.0996 9.09961l-39.1992 23c-7.60059 4.5 -10.1006 14.2002 -5.80078 21.9004l7.90039 13.8994c4.40039 7.7002 14 10.2998 21.5 5.90039l39.2002 -23
|
||||
l-9.10059 34.7002c-2.2998 8.5 2.7002 17.2998 11.1006 19.5996l15.2002 4.09961c8.39941 2.30078 17.0996 -2.7998 19.2998 -11.2998l21.2998 -81l71.9004 -42.2002v84.5l-58.3008 59.3008c-6.09961 6.19922 -6.09961 16.3994 0 22.5996l11.5 11.2998
|
||||
c6.10059 6.2002 16.1006 6.2002 22.2002 0l24.9004 -25.3994v46.0996c0 8.7998 7 16 15.7002 16h15.6992c8.7002 0 15.7002 -7.2002 15.7002 -16v-45.9004l24.9004 25.4004c6.09961 6.2002 16.0996 6.2002 22.2002 0l11.0996 -11.2998
|
||||
c6.09961 -6.2002 6.09961 -16.4004 0 -22.6006l-58.2998 -59.2998v-84.5l71.8994 42.2002l21.3008 81c2.2998 8.5 10.8994 13.5996 19.2998 11.2998l15.2002 -4.09961c8.39941 -2.2998 13.2998 -11.1006 11.0996 -19.6006l-9.09961 -34.6992l39.1992 23
|
||||
c7.5 4.39941 17.2002 1.7998 21.5 -5.90039l7.90039 -13.9004c4.2998 -7.69922 1.7002 -17.5 -5.7998 -21.8994l-39.2002 -23l34.0996 -9.2998c8.40039 -2.30078 13.3008 -11.1006 11.1006 -19.6006l-4.10059 -15.5c-2.2998 -8.5 -10.8994 -13.5996 -19.2998 -11.2998
|
||||
l-79.7002 21.7002l-71.8994 -42.2002l71.7998 -42.2002l79.7002 21.7002c8.39941 2.2998 17.0996 -2.7998 19.2998 -11.2998l4.09961 -15.5c2.30078 -8.5 -2.69922 -17.2998 -11.0996 -19.6006l-34.0996 -9.2998z" />
|
||||
<glyph glyph-name="trash-alt" unicode="" horiz-adv-x="448"
|
||||
d="M268 32c-6.62305 0 -12 5.37695 -12 12v216c0 6.62305 5.37695 12 12 12h24c6.62305 0 12 -5.37695 12 -12v-216c0 -6.62305 -5.37695 -12 -12 -12h-24zM432 368c8.83105 0 16 -7.16895 16 -16v-16c0 -8.83105 -7.16895 -16 -16 -16h-16v-336
|
||||
c0 -26.4922 -21.5078 -48 -48 -48h-288c-26.4922 0 -48 21.5078 -48 48v336h-16c-8.83105 0 -16 7.16895 -16 16v16c0 8.83105 7.16895 16 16 16h82.4102l34.0195 56.7002c8.39258 13.9844 23.6777 23.2998 41.1602 23.2998h100.82
|
||||
c0.0078125 0 -0.015625 0.0517578 -0.0078125 0.0517578c17.4824 0 32.7949 -9.36719 41.1875 -23.3516l34 -56.7002h82.4102zM171.84 397.09l-17.4502 -29.0898h139.221l-17.46 29.0898c-1.0498 1.74707 -2.95898 2.91016 -5.14355 2.91016h-0.00683594h-94
|
||||
c-0.00585938 0 -0.00683594 0.00683594 -0.0126953 0.00683594c-2.18457 0 -4.09766 -1.16992 -5.14746 -2.91699zM368 -16v336h-288v-336h288zM156 32c-6.62305 0 -12 5.37695 -12 12v216c0 6.62305 5.37695 12 12 12h24c6.62305 0 12 -5.37695 12 -12v-216
|
||||
c0 -6.62305 -5.37695 -12 -12 -12h-24z" />
|
||||
<glyph glyph-name="images" unicode="" horiz-adv-x="576"
|
||||
d="M480 32v-16c0 -26.5098 -21.4902 -48 -48 -48h-384c-26.5098 0 -48 21.4902 -48 48v256c0 26.5098 21.4902 48 48 48h16v-48h-10c-3.31152 0 -6 -2.68848 -6 -6v-244c0 -3.31152 2.68848 -6 6 -6h372c3.31152 0 6 2.68848 6 6v10h48zM522 368h-372
|
||||
c-3.31152 0 -6 -2.68848 -6 -6v-244c0 -3.31152 2.68848 -6 6 -6h372c3.31152 0 6 2.68848 6 6v244c0 3.31152 -2.68848 6 -6 6zM528 416c26.5098 0 48 -21.4902 48 -48v-256c0 -26.5098 -21.4902 -48 -48 -48h-384c-26.5098 0 -48 21.4902 -48 48v256
|
||||
c0 26.5098 21.4902 48 48 48h384zM264 304c0 -22.0908 -17.9092 -40 -40 -40s-40 17.9092 -40 40s17.9092 40 40 40s40 -17.9092 40 -40zM192 208l39.5146 39.5146c4.68652 4.68652 12.2842 4.68652 16.9717 0l39.5137 -39.5146l103.515 103.515
|
||||
c4.68652 4.68652 12.2842 4.68652 16.9717 0l71.5137 -71.5146v-80h-288v48z" />
|
||||
<glyph glyph-name="clipboard" unicode="" horiz-adv-x="384"
|
||||
d="M336 384c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h80c0 35.2998 28.7002 64 64 64s64 -28.7002 64 -64h80zM192 408c-13.2998 0 -24 -10.7002 -24 -24s10.7002 -24 24 -24s24 10.7002 24 24
|
||||
s-10.7002 24 -24 24zM336 -10v340c0 3.2998 -2.7002 6 -6 6h-42v-36c0 -6.59961 -5.40039 -12 -12 -12h-168c-6.59961 0 -12 5.40039 -12 12v36h-42c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h276c3.2998 0 6 2.7002 6 6z" />
|
||||
<glyph glyph-name="arrow-alt-circle-down" unicode=""
|
||||
d="M256 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM256 -8c110.5 0 200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200s89.5 -200 200 -200zM224 308c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-116
|
||||
h67c10.7002 0 16.0996 -12.9004 8.5 -20.5l-99 -99c-4.7002 -4.7002 -12.2998 -4.7002 -17 0l-99 99c-7.5 7.59961 -2.2002 20.5 8.5 20.5h67v116z" />
|
||||
<glyph glyph-name="arrow-alt-circle-left" unicode=""
|
||||
d="M8 192c0 137 111 248 248 248s248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248zM456 192c0 110.5 -89.5 200 -200 200s-200 -89.5 -200 -200s89.5 -200 200 -200s200 89.5 200 200zM384 212v-40c0 -6.59961 -5.40039 -12 -12 -12h-116v-67
|
||||
c0 -10.7002 -12.9004 -16 -20.5 -8.5l-99 99c-4.7002 4.7002 -4.7002 12.2998 0 17l99 99c7.59961 7.59961 20.5 2.2002 20.5 -8.5v-67h116c6.59961 0 12 -5.40039 12 -12z" />
|
||||
<glyph glyph-name="arrow-alt-circle-right" unicode=""
|
||||
d="M504 192c0 -137 -111 -248 -248 -248s-248 111 -248 248s111 248 248 248s248 -111 248 -248zM56 192c0 -110.5 89.5 -200 200 -200s200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200zM128 172v40c0 6.59961 5.40039 12 12 12h116v67
|
||||
c0 10.7002 12.9004 16 20.5 8.5l99 -99c4.7002 -4.7002 4.7002 -12.2998 0 -17l-99 -99c-7.59961 -7.59961 -20.5 -2.2002 -20.5 8.5v67h-116c-6.59961 0 -12 5.40039 -12 12z" />
|
||||
<glyph glyph-name="arrow-alt-circle-up" unicode=""
|
||||
d="M256 -56c-137 0 -248 111 -248 248s111 248 248 248s248 -111 248 -248s-111 -248 -248 -248zM256 392c-110.5 0 -200 -89.5 -200 -200s89.5 -200 200 -200s200 89.5 200 200s-89.5 200 -200 200zM276 64h-40c-6.59961 0 -12 5.40039 -12 12v116h-67
|
||||
c-10.7002 0 -16 12.9004 -8.5 20.5l99 99c4.7002 4.7002 12.2998 4.7002 17 0l99 -99c7.59961 -7.59961 2.2002 -20.5 -8.5 -20.5h-67v-116c0 -6.59961 -5.40039 -12 -12 -12z" />
|
||||
<glyph glyph-name="gem" unicode="" horiz-adv-x="576"
|
||||
d="M464 448c4.09961 0 7.7998 -2 10.0996 -5.40039l99.9004 -147.199c2.90039 -4.40039 2.59961 -10.1006 -0.700195 -14.2002l-276 -340.8c-4.7998 -5.90039 -13.7998 -5.90039 -18.5996 0l-276 340.8c-3.2998 4 -3.60059 9.7998 -0.700195 14.2002l100 147.199
|
||||
c2.2002 3.40039 6 5.40039 10 5.40039h352zM444.7 400h-56.7998l51.6992 -96h68.4004zM242.6 400l-51.5996 -96h194l-51.7002 96h-90.7002zM131.3 400l-63.2998 -96h68.4004l51.6992 96h-56.7998zM88.2998 256l119.7 -160l-68.2998 160h-51.4004zM191.2 256l96.7998 -243.3
|
||||
l96.7998 243.3h-193.6zM368 96l119.6 160h-51.3994z" />
|
||||
<glyph glyph-name="money-bill-alt" unicode="" horiz-adv-x="640"
|
||||
d="M320 304c53.0195 0 96 -50.1396 96 -112c0 -61.8701 -43 -112 -96 -112c-53.0195 0 -96 50.1504 -96 112c0 61.8604 42.9805 112 96 112zM360 136v16c0 4.41992 -3.58008 8 -8 8h-16v88c0 4.41992 -3.58008 8 -8 8h-13.5801
|
||||
c-4.91113 0 -9.50586 -1.49316 -13.3096 -4.03027l-15.3301 -10.2197c-2.15332 -1.43262 -3.55957 -3.88379 -3.55957 -6.66113c0 -1.6377 0.493164 -3.16113 1.33887 -4.42871l8.88086 -13.3105c1.43164 -2.15234 3.88379 -3.55957 6.66113 -3.55957
|
||||
c1.6377 0 3.16016 0.494141 4.42871 1.33984l0.469727 0.310547v-55.4404h-16c-4.41992 0 -8 -3.58008 -8 -8v-16c0 -4.41992 3.58008 -8 8 -8h64c4.41992 0 8 3.58008 8 8zM608 384c17.6699 0 32 -14.3301 32 -32v-320c0 -17.6699 -14.3301 -32 -32 -32h-576
|
||||
c-17.6699 0 -32 14.3301 -32 32v320c0 17.6699 14.3301 32 32 32h576zM592 112v160c-35.3496 0 -64 28.6504 -64 64h-416c0 -35.3496 -28.6504 -64 -64 -64v-160c35.3496 0 64 -28.6504 64 -64h416c0 35.3496 28.6504 64 64 64z" />
|
||||
<glyph glyph-name="window-close" unicode=""
|
||||
d="M464 416c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-416c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h416zM464 22v340c0 3.2998 -2.7002 6 -6 6h-404c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h404c3.2998 0 6 2.7002 6 6z
|
||||
M356.5 253.4l-61.4004 -61.4004l61.4004 -61.4004c4.59961 -4.59961 4.59961 -12.0996 0 -16.7998l-22.2998 -22.2998c-4.60059 -4.59961 -12.1006 -4.59961 -16.7998 0l-61.4004 61.4004l-61.4004 -61.4004c-4.59961 -4.59961 -12.0996 -4.59961 -16.7998 0
|
||||
l-22.2998 22.2998c-4.59961 4.60059 -4.59961 12.1006 0 16.7998l61.4004 61.4004l-61.4004 61.4004c-4.59961 4.59961 -4.59961 12.0996 0 16.7998l22.2998 22.2998c4.60059 4.59961 12.1006 4.59961 16.7998 0l61.4004 -61.4004l61.4004 61.4004
|
||||
c4.59961 4.59961 12.0996 4.59961 16.7998 0l22.2998 -22.2998c4.7002 -4.60059 4.7002 -12.1006 0 -16.7998z" />
|
||||
<glyph glyph-name="comment-dots" unicode=""
|
||||
d="M144 240c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM256 240c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM368 240c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32
|
||||
s-32 14.2998 -32 32s14.2998 32 32 32zM256 416c141.4 0 256 -93.0996 256 -208s-114.6 -208 -256 -208c-32.7998 0 -64 5.2002 -92.9004 14.2998c-29.0996 -20.5996 -77.5996 -46.2998 -139.1 -46.2998c-9.59961 0 -18.2998 5.7002 -22.0996 14.5
|
||||
c-3.80078 8.7998 -2 19 4.59961 26c0.5 0.400391 31.5 33.7998 46.4004 73.2002c-33 35.0996 -52.9004 78.7002 -52.9004 126.3c0 114.9 114.6 208 256 208zM256 48c114.7 0 208 71.7998 208 160s-93.2998 160 -208 160s-208 -71.7998 -208 -160
|
||||
c0 -42.2002 21.7002 -74.0996 39.7998 -93.4004l20.6006 -21.7998l-10.6006 -28.0996c-5.5 -14.5 -12.5996 -28.1006 -19.8994 -40.2002c23.5996 7.59961 43.1992 18.9004 57.5 29l19.5 13.7998l22.6992 -7.2002c25.3008 -8 51.7002 -12.0996 78.4004 -12.0996z" />
|
||||
<glyph glyph-name="smile-wink" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM365.8 138.4c10.2002 -8.5 11.6006 -23.6006 3.10059 -33.8008
|
||||
c-30 -36 -74.1006 -56.5996 -120.9 -56.5996s-90.9004 20.5996 -120.9 56.5996c-8.39941 10.2002 -7.09961 25.3008 3.10059 33.8008c10.0996 8.39941 25.2998 7.09961 33.7998 -3.10059c20.7998 -25.0996 51.5 -39.3994 84 -39.3994s63.2002 14.3994 84 39.3994
|
||||
c8.5 10.2002 23.5996 11.6006 33.7998 3.10059zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 268c25.7002 0 55.9004 -16.9004 59.7002 -42.0996c1.7998 -11.1006 -11.2998 -18.2002 -19.7998 -10.8008l-9.5 8.5
|
||||
c-14.8008 13.2002 -46.2002 13.2002 -61 0l-9.5 -8.5c-8.30078 -7.39941 -21.5 -0.399414 -19.8008 10.8008c4 25.1992 34.2002 42.0996 59.9004 42.0996z" />
|
||||
<glyph glyph-name="angry" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM248 136c33.5996 0 65.2002 -14.7998 86.7998 -40.5996
|
||||
c8.40039 -10.2002 7.10059 -25.3008 -3.09961 -33.8008c-10.6006 -8.89941 -25.7002 -6.69922 -33.7998 3c-24.8008 29.7002 -75 29.7002 -99.8008 0c-8.5 -10.1992 -23.5996 -11.5 -33.7998 -3s-11.5996 23.6006 -3.09961 33.8008
|
||||
c21.5996 25.7998 53.2002 40.5996 86.7998 40.5996zM200 208c0 -17.7002 -14.2998 -32.0996 -32 -32.0996s-32 14.2998 -32 32c0 6.19922 2.2002 11.6992 5.2998 16.5996l-28.2002 8.5c-12.6992 3.7998 -19.8994 17.2002 -16.0996 29.9004
|
||||
c3.7998 12.6992 17.0996 20 29.9004 16.0996l80 -24c12.6992 -3.7998 19.8994 -17.2002 16.0996 -29.9004c-3.09961 -10.3994 -12.7002 -17.0996 -23 -17.0996zM399 262.9c3.7998 -12.7002 -3.40039 -26.1006 -16.0996 -29.8008l-28.2002 -8.5
|
||||
c3.09961 -4.89941 5.2998 -10.3994 5.2998 -16.5996c0 -17.7002 -14.2998 -32 -32 -32s-32 14.2998 -32 32c-10.2998 0 -19.9004 6.7002 -23 17.0996c-3.7998 12.7002 3.40039 26.1006 16.0996 29.9004l80 24c12.8008 3.7998 26.1006 -3.40039 29.9004 -16.0996z" />
|
||||
<glyph glyph-name="dizzy" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM214.2 209.9
|
||||
c-7.90039 -7.90039 -20.5 -7.90039 -28.4004 -0.200195l-17.7998 17.7998l-17.7998 -17.7998c-7.7998 -7.7998 -20.5 -7.7998 -28.2998 0c-7.80078 7.7998 -7.80078 20.5 0 28.2998l17.8994 17.9004l-17.8994 17.8994c-7.80078 7.7998 -7.80078 20.5 0 28.2998
|
||||
c7.7998 7.80078 20.5 7.80078 28.2998 0l17.7998 -17.7998l17.9004 17.9004c7.7998 7.7998 20.5 7.7998 28.2998 0s7.7998 -20.5 0 -28.2998l-17.9004 -17.9004l17.9004 -17.7998c7.7998 -7.7998 7.7998 -20.5 0 -28.2998zM374.2 302.1
|
||||
c7.7002 -7.7998 7.7002 -20.3994 0 -28.1992l-17.9004 -17.9004l17.7998 -18c7.80078 -7.7998 7.80078 -20.5 0 -28.2998c-7.7998 -7.7998 -20.5 -7.7998 -28.2998 0l-17.7998 17.7998l-17.7998 -17.7998c-7.7998 -7.7998 -20.5 -7.7998 -28.2998 0
|
||||
c-7.80078 7.7998 -7.80078 20.5 0 28.2998l17.8994 17.9004l-17.8994 17.8994c-7.80078 7.7998 -7.80078 20.5 0 28.2998c7.7998 7.80078 20.5 7.80078 28.2998 0l17.7998 -17.7998l17.9004 17.7998c7.7998 7.80078 20.5 7.80078 28.2998 0zM248 176
|
||||
c35.2998 0 64 -28.7002 64 -64s-28.7002 -64 -64 -64s-64 28.7002 -64 64s28.7002 64 64 64z" />
|
||||
<glyph glyph-name="flushed" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM344 304c44.2002 0 80 -35.7998 80 -80s-35.7998 -80 -80 -80
|
||||
s-80 35.7998 -80 80s35.7998 80 80 80zM344 176c26.5 0 48 21.5 48 48s-21.5 48 -48 48s-48 -21.5 -48 -48s21.5 -48 48 -48zM344 248c13.2998 0 24 -10.7002 24 -24s-10.7002 -24 -24 -24s-24 10.7002 -24 24s10.7002 24 24 24zM232 224c0 -44.2002 -35.7998 -80 -80 -80
|
||||
s-80 35.7998 -80 80s35.7998 80 80 80s80 -35.7998 80 -80zM152 176c26.5 0 48 21.5 48 48s-21.5 48 -48 48s-48 -21.5 -48 -48s21.5 -48 48 -48zM152 248c13.2998 0 24 -10.7002 24 -24s-10.7002 -24 -24 -24s-24 10.7002 -24 24s10.7002 24 24 24zM312 104
|
||||
c13.2002 0 24 -10.7998 24 -24s-10.7998 -24 -24 -24h-128c-13.2002 0 -24 10.7998 -24 24s10.7998 24 24 24h128z" />
|
||||
<glyph glyph-name="frown-open" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM200 240c0 -17.7002 -14.2998 -32 -32 -32s-32 14.2998 -32 32
|
||||
s14.2998 32 32 32s32 -14.2998 32 -32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM248 160c35.5996 0 88.7998 -21.2998 95.7998 -61.2002c2 -11.7998 -9.09961 -21.5996 -20.5 -18.0996
|
||||
c-31.2002 9.59961 -59.3994 15.2998 -75.2998 15.2998s-44.0996 -5.7002 -75.2998 -15.2998c-11.5 -3.40039 -22.5 6.2998 -20.5 18.0996c7 39.9004 60.2002 61.2002 95.7998 61.2002z" />
|
||||
<glyph glyph-name="grimace" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32
|
||||
s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM344 192c26.5 0 48 -21.5 48 -48v-32c0 -26.5 -21.5 -48 -48 -48h-192c-26.5 0 -48 21.5 -48 48v32c0 26.5 21.5 48 48 48
|
||||
h192zM176 96v24h-40v-8c0 -8.7998 7.2002 -16 16 -16h24zM176 136v24h-24c-8.7998 0 -16 -7.2002 -16 -16v-8h40zM240 96v24h-48v-24h48zM240 136v24h-48v-24h48zM304 96v24h-48v-24h48zM304 136v24h-48v-24h48zM360 112v8h-40v-24h24c8.7998 0 16 7.2002 16 16zM360 136v8
|
||||
c0 8.7998 -7.2002 16 -16 16h-24v-24h40z" />
|
||||
<glyph glyph-name="grin" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM353.6 143.4c10 3.09961 19.3008 -5.5 17.7002 -15.3008
|
||||
c-8 -47.0996 -71.2998 -80 -123.3 -80s-115.4 32.9004 -123.3 80c-1.7002 9.90039 7.7998 18.4004 17.7002 15.3008c26 -8.30078 64.3994 -13.1006 105.6 -13.1006s79.7002 4.7998 105.6 13.1006zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32
|
||||
s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32z" />
|
||||
<glyph glyph-name="grin-alt" unicode="" horiz-adv-x="496"
|
||||
d="M200.3 200c-7.5 -11.4004 -24.5996 -12 -32.7002 0c-12.3994 18.7002 -15.1992 37.2998 -15.6992 56c0.599609 18.7002 3.2998 37.2998 15.6992 56c7.60059 11.4004 24.7002 12 32.7002 0c12.4004 -18.7002 15.2002 -37.2998 15.7002 -56
|
||||
c-0.599609 -18.7002 -3.2998 -37.2998 -15.7002 -56zM328.3 200c-7.5 -11.4004 -24.5996 -12 -32.7002 0c-12.3994 18.7002 -15.1992 37.2998 -15.6992 56c0.599609 18.7002 3.2998 37.2998 15.6992 56c7.60059 11.4004 24.7002 12 32.7002 0
|
||||
c12.4004 -18.7002 15.2002 -37.2998 15.7002 -56c-0.599609 -18.7002 -3.2998 -37.2998 -15.7002 -56zM248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200
|
||||
s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM353.6 143.4c10 3.09961 19.3008 -5.5 17.7002 -15.3008c-8 -47.0996 -71.2998 -80 -123.3 -80s-115.4 32.8008 -123.3 80c-1.7002 10 7.7998 18.4004 17.7002 15.3008c26 -8.30078 64.3994 -13.1006 105.6 -13.1006
|
||||
s79.7002 4.7998 105.6 13.1006z" />
|
||||
<glyph glyph-name="grin-beam" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM353.6 143.4c10 3.09961 19.3008 -5.5 17.7002 -15.3008
|
||||
c-8 -47.0996 -71.2998 -80 -123.3 -80s-115.4 32.9004 -123.3 80c-1.7002 10 7.89941 18.4004 17.7002 15.3008c26 -8.30078 64.3994 -13.1006 105.6 -13.1006s79.7002 4.7998 105.6 13.1006zM117.7 216.3c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998
|
||||
c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998c-3.09961 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996s-23.7998 -7.89941 -31.5 -21.5996
|
||||
l-9.5 -17c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002zM277.7 216.3c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998
|
||||
c-3.09961 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996s-23.7998 -7.89941 -31.5 -21.5996l-9.5 -17c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002z" />
|
||||
<glyph glyph-name="grin-beam-sweat" unicode="" horiz-adv-x="496"
|
||||
d="M440 288c-29.5 0 -53.2998 26.2998 -53.2998 58.7002c0 25 31.7002 75.5 46.2002 97.2998c3.5 5.2998 10.5996 5.2998 14.1992 0c14.5 -21.7998 46.2002 -72.2998 46.2002 -97.2998c0 -32.4004 -23.7998 -58.7002 -53.2998 -58.7002zM248 48
|
||||
c-51.9004 0 -115.3 32.9004 -123.3 80c-1.7002 10 7.89941 18.4004 17.7002 15.2998c26 -8.2998 64.3994 -13.0996 105.6 -13.0996s79.7002 4.7998 105.6 13.0996c10 3.2002 19.4004 -5.39941 17.7002 -15.2998c-8 -47.0996 -71.3994 -80 -123.3 -80zM378.3 216.3
|
||||
c-3.09961 -0.899414 -7.2002 0.100586 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996s-23.7998 -7.89941 -31.5 -21.5996l-9.5 -17c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998
|
||||
c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998zM483.6 269.2c8 -24.2998 12.4004 -50.2002 12.4004 -77.2002c0 -137 -111 -248 -248 -248s-248 111 -248 248s111 248 248 248
|
||||
c45.7002 0 88.4004 -12.5996 125.2 -34.2002c-10.9004 -21.5996 -15.5 -36.2002 -17.2002 -45.7002c-31.2002 20.1006 -68.2002 31.9004 -108 31.9004c-110.3 0 -200 -89.7002 -200 -200s89.7002 -200 200 -200s200 89.7002 200 200
|
||||
c0 22.5 -3.90039 44.0996 -10.7998 64.2998c0.399414 0 21.7998 -2.7998 46.3994 12.9004zM168 258.6c-12.2998 0 -23.7998 -7.7998 -31.5 -21.5996l-9.5 -17c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998
|
||||
c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998c-3.09961 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996z" />
|
||||
<glyph glyph-name="grin-hearts" unicode="" horiz-adv-x="496"
|
||||
d="M353.6 143.4c10 3.09961 19.3008 -5.5 17.7002 -15.3008c-8 -47.0996 -71.2998 -80 -123.3 -80s-115.4 32.8008 -123.3 80c-1.7002 10 7.89941 18.4004 17.7002 15.3008c26 -8.30078 64.3994 -13.1006 105.6 -13.1006s79.7002 4.7998 105.6 13.1006zM200.8 192.3
|
||||
l-70.2002 18.1006c-20.3994 5.2998 -31.8994 27 -24.1992 47.1992c6.69922 17.7002 26.6992 26.7002 44.8994 22l7.10059 -1.89941l2 7.09961c5.09961 18.1006 22.8994 30.9004 41.5 27.9004c21.3994 -3.40039 34.3994 -24.2002 28.7998 -44.5l-19.4004 -69.9004
|
||||
c-1.2998 -4.5 -6 -7.2002 -10.5 -6zM389.6 257.6c7.7002 -20.1992 -3.7998 -41.7998 -24.1992 -47.0996l-70.2002 -18.2002c-4.60059 -1.2002 -9.2998 1.5 -10.5 6l-19.4004 69.9004c-5.59961 20.2998 7.40039 41.0996 28.7998 44.5c18.7002 3 36.5 -9.7998 41.5 -27.9004
|
||||
l2 -7.09961l7.10059 1.89941c18.2002 4.7002 38.2002 -4.39941 44.8994 -22zM248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200
|
||||
s89.7002 -200 200 -200z" />
|
||||
<glyph glyph-name="grin-squint" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM353.6 143.4c10 3.09961 19.3008 -5.5 17.7002 -15.3008
|
||||
c-8 -47.0996 -71.2998 -80 -123.3 -80s-115.4 32.9004 -123.3 80c-1.7002 9.90039 7.7998 18.4004 17.7002 15.3008c26 -8.30078 64.3994 -13.1006 105.6 -13.1006s79.7002 4.7998 105.6 13.1006zM118.9 184.2c-3.80078 4.39941 -3.90039 11 -0.100586 15.5l33.6006 40.2998
|
||||
l-33.6006 40.2998c-3.7002 4.5 -3.7002 11 0.100586 15.5c3.89941 4.40039 10.1992 5.5 15.2998 2.5l80 -48c3.59961 -2.2002 5.7998 -6.09961 5.7998 -10.2998s-2.2002 -8.09961 -5.7998 -10.2998l-80 -48c-5.40039 -3.2002 -11.7002 -1.7002 -15.2998 2.5zM361.8 181.7
|
||||
l-80 48c-3.59961 2.2002 -5.7998 6.09961 -5.7998 10.2998s2.2002 8.09961 5.7998 10.2998l80 48c5.10059 2.90039 11.5 1.90039 15.2998 -2.5c3.80078 -4.5 3.90039 -11 0.100586 -15.5l-33.6006 -40.2998l33.6006 -40.2998c3.7002 -4.5 3.7002 -11 -0.100586 -15.5
|
||||
c-3.59961 -4.2002 -9.89941 -5.7002 -15.2998 -2.5z" />
|
||||
<glyph glyph-name="grin-squint-tears" unicode=""
|
||||
d="M117.1 63.9004c6.30078 0.899414 11.7002 -4.5 10.9004 -10.9004c-3.7002 -25.7998 -13.7002 -84 -30.5996 -100.9c-22 -21.8994 -57.9004 -21.5 -80.3008 0.900391c-22.3994 22.4004 -22.7998 58.4004 -0.899414 80.2998
|
||||
c16.8994 16.9004 75.0996 26.9004 100.899 30.6006zM75.9004 105.6c-19.6006 -3.89941 -35.1006 -8.09961 -47.3008 -12.1992c-39.2998 90.5996 -22.0996 199.899 52 274c48.5 48.3994 111.9 72.5996 175.4 72.5996c38.9004 0 77.7998 -9.2002 113.2 -27.4004
|
||||
c-4 -12.1992 -8.2002 -28 -12 -48.2998c-30.4004 17.9004 -65 27.7002 -101.2 27.7002c-53.4004 0 -103.6 -20.7998 -141.4 -58.5996c-61.5996 -61.5 -74.2998 -153.4 -38.6992 -227.801zM428.2 293.2c20.2998 3.89941 36.2002 8 48.5 12
|
||||
c47.8994 -93.2002 32.8994 -210.5 -45.2002 -288.601c-48.5 -48.3994 -111.9 -72.5996 -175.4 -72.5996c-33.6992 0 -67.2998 7 -98.6992 20.5996c4.19922 12.2002 8.2998 27.7002 12.1992 47.2002c26.6006 -12.7998 55.9004 -19.7998 86.4004 -19.7998
|
||||
c53.4004 0 103.6 20.7998 141.4 58.5996c65.6992 65.7002 75.7998 166 30.7998 242.601zM394.9 320.1c-6.30078 -0.899414 -11.7002 4.5 -10.9004 10.9004c3.7002 25.7998 13.7002 84 30.5996 100.9c22 21.8994 57.9004 21.5 80.3008 -0.900391
|
||||
c22.3994 -22.4004 22.7998 -58.4004 0.899414 -80.2998c-16.8994 -16.9004 -75.0996 -26.9004 -100.899 -30.6006zM207.9 211.8c3 -3 4.19922 -7.2998 3.19922 -11.5l-22.5996 -90.5c-1.40039 -5.39941 -6.2002 -9.09961 -11.7002 -9.09961h-0.899414
|
||||
c-5.80078 0.5 -10.5 5.09961 -11 10.8994l-4.80078 52.3008l-52.2998 4.7998c-5.7998 0.5 -10.3994 5.2002 -10.8994 11c-0.400391 5.89941 3.39941 11.2002 9.09961 12.5996l90.5 22.7002c4.2002 1 8.40039 -0.200195 11.4004 -3.2002zM247.6 236.9
|
||||
c-0.0996094 0 -6.39941 -1.80078 -11.3994 3.19922c-3 3 -4.2002 7.30078 -3.2002 11.4004l22.5996 90.5c1.40039 5.7002 7 9.2002 12.6006 9.09961c5.7998 -0.5 10.5 -5.09961 11 -10.8994l4.7998 -52.2998l52.2998 -4.80078c5.7998 -0.5 10.4004 -5.19922 10.9004 -11
|
||||
c0.399414 -5.89941 -3.40039 -11.1992 -9.10059 -12.5996zM299.6 148.4c29.1006 29.0996 53 59.5996 65.3008 83.7998c4.89941 9.2998 17.5996 9.89941 23.3994 1.7002c27.7002 -38.9004 6.10059 -106.9 -30.5996 -143.7s-104.8 -58.2998 -143.7 -30.6006
|
||||
c-8.2998 5.90039 -7.5 18.6006 1.7002 23.4004c24.2002 12.5 54.7998 36.2998 83.8994 65.4004z" />
|
||||
<glyph glyph-name="grin-stars" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM353.6 143.4c10 3.09961 19.3008 -5.5 17.7002 -15.3008
|
||||
c-8 -47.0996 -71.2998 -80 -123.3 -80s-115.4 32.8008 -123.3 80c-1.7002 10 7.89941 18.4004 17.7002 15.3008c26 -8.30078 64.3994 -13.1006 105.6 -13.1006s79.7002 4.7998 105.6 13.1006zM125.7 200.9l6.09961 34.8994l-25.3994 24.6006
|
||||
c-4.60059 4.59961 -1.90039 12.2998 4.2998 13.1992l34.8994 5l15.5 31.6006c2.90039 5.7998 11 5.7998 13.9004 0l15.5 -31.6006l34.9004 -5c6.19922 -1 8.7998 -8.69922 4.2998 -13.1992l-25.4004 -24.6006l6 -34.8994c1 -6.2002 -5.39941 -11 -11 -7.90039
|
||||
l-31.2998 16.2998l-31.2998 -16.2998c-5.60059 -3.09961 -12 1.7002 -11 7.90039zM385.4 273.6c6.19922 -1 8.89941 -8.59961 4.39941 -13.1992l-25.3994 -24.6006l6 -34.8994c1 -6.2002 -5.40039 -11 -11 -7.90039l-31.3008 16.2998l-31.2998 -16.2998
|
||||
c-5.59961 -3.09961 -12 1.7002 -11 7.90039l6 34.8994l-25.3994 24.6006c-4.60059 4.59961 -1.90039 12.2998 4.2998 13.1992l34.8994 5l15.5 31.6006c2.90039 5.7998 11 5.7998 13.9004 0l15.5 -31.6006z" />
|
||||
<glyph glyph-name="grin-tears" unicode="" horiz-adv-x="640"
|
||||
d="M117.1 191.9c6.30078 0.899414 11.7002 -4.5 10.9004 -10.9004c-3.7002 -25.7998 -13.7002 -84 -30.5996 -100.9c-22 -21.8994 -57.9004 -21.5 -80.3008 0.900391c-22.3994 22.4004 -22.7998 58.4004 -0.899414 80.2998c16.8994 16.9004 75.0996 26.9004 100.899 30.6006
|
||||
zM623.8 161.3c21.9004 -21.8994 21.5 -57.8994 -0.799805 -80.2002c-22.4004 -22.3994 -58.4004 -22.7998 -80.2998 -0.899414c-16.9004 16.8994 -26.9004 75.0996 -30.6006 100.899c-0.899414 6.30078 4.5 11.7002 10.8008 10.8008
|
||||
c25.7998 -3.7002 84 -13.7002 100.899 -30.6006zM497.2 99.5996c12.3994 -37.2998 25.0996 -43.7998 28.2998 -46.5c-44.5996 -65.7998 -120 -109.1 -205.5 -109.1s-160.9 43.2998 -205.5 109.1c3.09961 2.60059 15.7998 9.10059 28.2998 46.5
|
||||
c33.4004 -63.8994 100.3 -107.6 177.2 -107.6s143.8 43.7002 177.2 107.6zM122.7 223.5c-2.40039 0.299805 -5 2.5 -49.5 -6.90039c12.3994 125.4 118.1 223.4 246.8 223.4s234.4 -98 246.8 -223.5c-44.2998 9.40039 -47.3994 7.2002 -49.5 7
|
||||
c-15.2002 95.2998 -97.7998 168.5 -197.3 168.5s-182.1 -73.2002 -197.3 -168.5zM320 48c-51.9004 0 -115.3 32.9004 -123.3 80c-1.7002 10 7.89941 18.4004 17.7002 15.2998c26 -8.2998 64.3994 -13.0996 105.6 -13.0996s79.7002 4.7998 105.6 13.0996
|
||||
c10 3.2002 19.4004 -5.39941 17.7002 -15.2998c-8 -47.0996 -71.3994 -80 -123.3 -80zM450.3 216.3c-3.09961 -0.899414 -7.2002 0.100586 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996s-23.7998 -7.89941 -31.5 -21.5996l-9.5 -17
|
||||
c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998zM240 258.6
|
||||
c-12.2998 0 -23.7998 -7.7998 -31.5 -21.5996l-9.5 -17c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004
|
||||
c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998c-3.09961 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996z" />
|
||||
<glyph glyph-name="grin-tongue" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM312 40h0.0996094v43.7998l-17.6992 8.7998c-15.1006 7.60059 -31.5 -1.69922 -34.9004 -16.5l-2.7998 -12.0996c-2.10059 -9.2002 -15.2002 -9.2002 -17.2998 0
|
||||
l-2.80078 12.0996c-3.39941 14.8008 -19.8994 24 -34.8994 16.5l-17.7002 -8.7998v-42.7998c0 -35.2002 28 -64.5 63.0996 -65c35.8008 -0.5 64.9004 28.4004 64.9004 64zM340.2 14.7002c64 33.3994 107.8 100.3 107.8 177.3c0 110.3 -89.7002 200 -200 200
|
||||
s-200 -89.7002 -200 -200c0 -77 43.7998 -143.9 107.8 -177.3c-2.2002 8.09961 -3.7998 16.5 -3.7998 25.2998v43.5c-14.2002 12.4004 -24.4004 27.5 -27.2998 44.5c-1.7002 10 7.7998 18.4004 17.7002 15.2998c26 -8.2998 64.3994 -13.0996 105.6 -13.0996
|
||||
s79.7002 4.7998 105.6 13.0996c10 3.2002 19.4004 -5.39941 17.7002 -15.2998c-2.89941 -17 -13.0996 -32.0996 -27.2998 -44.5v-43.5c0 -8.7998 -1.59961 -17.2002 -3.7998 -25.2998zM168 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32
|
||||
s14.2998 32 32 32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32z" />
|
||||
<glyph glyph-name="grin-tongue-squint" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM312 40h0.0996094v43.7998l-17.6992 8.7998c-15.1006 7.60059 -31.5 -1.69922 -34.9004 -16.5l-2.7998 -12.0996c-2.10059 -9.2002 -15.2002 -9.2002 -17.2998 0
|
||||
l-2.80078 12.0996c-3.39941 14.8008 -19.8994 24 -34.8994 16.5l-17.7002 -8.7998v-42.7998c0 -35.2002 28 -64.5 63.0996 -65c35.8008 -0.5 64.9004 28.4004 64.9004 64zM340.2 14.7002c64 33.3994 107.8 100.3 107.8 177.3c0 110.3 -89.7002 200 -200 200
|
||||
s-200 -89.7002 -200 -200c0 -77 43.7998 -143.9 107.8 -177.3c-2.2002 8.09961 -3.7998 16.5 -3.7998 25.2998v43.5c-14.2002 12.4004 -24.4004 27.5 -27.2998 44.5c-1.7002 10 7.7998 18.4004 17.7002 15.2998c26 -8.2998 64.3994 -13.0996 105.6 -13.0996
|
||||
s79.7002 4.7998 105.6 13.0996c10 3.2002 19.4004 -5.39941 17.7002 -15.2998c-2.89941 -17 -13.0996 -32.0996 -27.2998 -44.5v-43.5c0 -8.7998 -1.59961 -17.2002 -3.7998 -25.2998zM377.1 295.8c3.80078 -4.39941 3.90039 -11 0.100586 -15.5l-33.6006 -40.2998
|
||||
l33.6006 -40.2998c3.7002 -4.5 3.7002 -11 -0.100586 -15.5c-3.59961 -4.2002 -9.89941 -5.7002 -15.2998 -2.5l-80 48c-3.59961 2.2002 -5.7998 6.09961 -5.7998 10.2998s2.2002 8.09961 5.7998 10.2998l80 48c5 3 11.5 1.90039 15.2998 -2.5zM214.2 250.3
|
||||
c3.59961 -2.2002 5.7998 -6.09961 5.7998 -10.2998s-2.2002 -8.09961 -5.7998 -10.2998l-80 -48c-5.40039 -3.2002 -11.7002 -1.7002 -15.2998 2.5c-3.80078 4.5 -3.90039 11 -0.100586 15.5l33.6006 40.2998l-33.6006 40.2998c-3.7002 4.5 -3.7002 11 0.100586 15.5
|
||||
c3.89941 4.5 10.2998 5.5 15.2998 2.5z" />
|
||||
<glyph glyph-name="grin-tongue-wink" unicode="" horiz-adv-x="496"
|
||||
d="M152 268c25.7002 0 55.9004 -16.9004 59.7998 -42.0996c0.799805 -5 -1.7002 -10 -6.09961 -12.4004c-5.7002 -3.09961 -11.2002 -0.599609 -13.7002 1.59961l-9.5 8.5c-14.7998 13.2002 -46.2002 13.2002 -61 0l-9.5 -8.5
|
||||
c-3.7998 -3.39941 -9.2998 -4 -13.7002 -1.59961c-4.39941 2.40039 -6.89941 7.40039 -6.09961 12.4004c3.89941 25.1992 34.0996 42.0996 59.7998 42.0996zM328 320c44.2002 0 80 -35.7998 80 -80s-35.7998 -80 -80 -80s-80 35.7998 -80 80s35.7998 80 80 80zM328 192
|
||||
c26.5 0 48 21.5 48 48s-21.5 48 -48 48s-48 -21.5 -48 -48s21.5 -48 48 -48zM328 264c13.2998 0 24 -10.7002 24 -24s-10.7002 -24 -24 -24s-24 10.7002 -24 24s10.7002 24 24 24zM248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248z
|
||||
M312 40h0.0996094v43.7998l-17.6992 8.7998c-15.1006 7.60059 -31.5 -1.69922 -34.9004 -16.5l-2.7998 -12.0996c-2.10059 -9.2002 -15.2002 -9.2002 -17.2998 0l-2.80078 12.0996c-3.39941 14.8008 -19.8994 24 -34.8994 16.5l-17.7002 -8.7998v-42.7998
|
||||
c0 -35.2002 28 -64.5 63.0996 -65c35.8008 -0.5 64.9004 28.4004 64.9004 64zM340.2 14.7002c64 33.3994 107.8 100.3 107.8 177.3c0 110.3 -89.7002 200 -200 200s-200 -89.7002 -200 -200c0 -77 43.7998 -143.9 107.8 -177.3
|
||||
c-2.2002 8.09961 -3.7998 16.5 -3.7998 25.2998v43.5c-14.2002 12.4004 -24.4004 27.5 -27.2998 44.5c-1.7002 10 7.7998 18.4004 17.7002 15.2998c26 -8.2998 64.3994 -13.0996 105.6 -13.0996s79.7002 4.7998 105.6 13.0996c10 3.2002 19.4004 -5.39941 17.7002 -15.2998
|
||||
c-2.89941 -17 -13.0996 -32.0996 -27.2998 -44.5v-43.5c0 -8.7998 -1.59961 -17.2002 -3.7998 -25.2998z" />
|
||||
<glyph glyph-name="grin-wink" unicode="" horiz-adv-x="496"
|
||||
d="M328 268c25.6904 0 55.8799 -16.9199 59.8701 -42.1201c1.72949 -11.0898 -11.3506 -18.2695 -19.8301 -10.8398l-9.5498 8.47949c-14.8105 13.1904 -46.1602 13.1904 -60.9707 0l-9.5498 -8.47949c-8.33008 -7.40039 -21.5801 -0.379883 -19.8301 10.8398
|
||||
c3.98047 25.2002 34.1699 42.1201 59.8604 42.1201zM168 208c-17.6699 0 -32 14.3301 -32 32s14.3301 32 32 32s32 -14.3301 32 -32s-14.3301 -32 -32 -32zM353.55 143.36c10.04 3.13965 19.3906 -5.4502 17.71 -15.3408
|
||||
c-7.92969 -47.1494 -71.3193 -80.0195 -123.26 -80.0195s-115.33 32.8701 -123.26 80.0195c-1.69043 9.9707 7.76953 18.4707 17.71 15.3408c25.9297 -8.31055 64.3994 -13.0605 105.55 -13.0605s79.6201 4.75977 105.55 13.0605zM248 440c136.97 0 248 -111.03 248 -248
|
||||
s-111.03 -248 -248 -248s-248 111.03 -248 248s111.03 248 248 248zM248 -8c110.28 0 200 89.7197 200 200s-89.7197 200 -200 200s-200 -89.7197 -200 -200s89.7197 -200 200 -200z" />
|
||||
<glyph glyph-name="kiss" unicode="" horiz-adv-x="496"
|
||||
d="M168 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM304 140c0 -13 -13.4004 -27.2998 -35.0996 -36.4004c21.7998 -8.69922 35.1992 -23 35.1992 -36c0 -19.1992 -28.6992 -41.5 -71.5 -44h-0.5
|
||||
c-3.69922 0 -7 2.60059 -7.7998 6.2002c-0.899414 3.7998 1.10059 7.7002 4.7002 9.2002l17 7.2002c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.2002c-6 2.59961 -5.7002 12.3994 0 14.7998l17 7.2002
|
||||
c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.19922c-3.59961 1.5 -5.59961 5.40039 -4.7002 9.2002c0.799805 3.7998 4.40039 6.60059 8.2002 6.2002c42.7002 -2.5 71.5 -24.7998 71.5 -44zM248 440c137 0 248 -111 248 -248
|
||||
s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32z
|
||||
" />
|
||||
<glyph glyph-name="kiss-beam" unicode="" horiz-adv-x="496"
|
||||
d="M168 296c23.7998 0 52.7002 -29.2998 55.7998 -71.4004c0.299805 -3.7998 -2 -7.19922 -5.59961 -8.2998c-3.10059 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996c-12.3008 0 -23.8008 -7.89941 -31.5 -21.5996l-9.5 -17
|
||||
c-1.80078 -3.2002 -5.80078 -4.7002 -9.30078 -3.7002c-3.59961 1.10059 -5.89941 4.60059 -5.59961 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004zM248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8
|
||||
c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM304 140c0 -13 -13.4004 -27.2998 -35.0996 -36.4004c21.7998 -8.69922 35.1992 -23 35.1992 -36c0 -19.1992 -28.6992 -41.5 -71.5 -44h-0.5
|
||||
c-3.69922 0 -7 2.60059 -7.7998 6.2002c-0.899414 3.7998 1.10059 7.7002 4.7002 9.2002l17 7.2002c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.2002c-6 2.59961 -5.7002 12.3994 0 14.7998l17 7.2002
|
||||
c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.19922c-3.59961 1.5 -5.59961 5.40039 -4.7002 9.2002c0.799805 3.7998 4.40039 6.60059 8.2002 6.2002c42.7002 -2.5 71.5 -24.7998 71.5 -44zM328 296
|
||||
c23.7998 0 52.7002 -29.2998 55.7998 -71.4004c0.299805 -3.7998 -2 -7.19922 -5.59961 -8.2998c-3.10059 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996c-12.3008 0 -23.8008 -7.89941 -31.5 -21.5996l-9.5 -17
|
||||
c-1.80078 -3.2002 -5.80078 -4.7002 -9.30078 -3.7002c-3.59961 1.10059 -5.89941 4.60059 -5.59961 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004z" />
|
||||
<glyph glyph-name="kiss-wink-heart" unicode="" horiz-adv-x="504"
|
||||
d="M304 139.5c0 -13 -13.4004 -27.2998 -35.0996 -36.4004c21.7998 -8.69922 35.1992 -23 35.1992 -36c0 -19.1992 -28.6992 -41.5 -71.5 -44h-0.5c-3.69922 0 -7 2.60059 -7.7998 6.2002c-0.899414 3.7998 1.10059 7.7002 4.7002 9.2002l17 7.2002
|
||||
c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.2002c-6 2.59961 -5.7002 12.3994 0 14.7998l17 7.2002c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.19922c-3.59961 1.5 -5.59961 5.40039 -4.7002 9.2002
|
||||
c0.799805 3.7998 4.40039 6.60059 8.2002 6.2002c42.7002 -2.5 71.5 -24.7998 71.5 -44zM374.5 223c-14.7998 13.2002 -46.2002 13.2002 -61 0l-9.5 -8.5c-2.5 -2.2998 -7.90039 -4.7002 -13.7002 -1.59961c-4.39941 2.39941 -6.89941 7.39941 -6.09961 12.3994
|
||||
c3.89941 25.2002 34.2002 42.1006 59.7998 42.1006s55.7998 -16.9004 59.7998 -42.1006c0.799805 -5 -1.7002 -10 -6.09961 -12.3994c-4.40039 -2.40039 -9.90039 -1.7002 -13.7002 1.59961zM136 239.5c0 17.7002 14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32
|
||||
s-32 14.2998 -32 32zM501.1 45.5c9.2002 -23.9004 -4.39941 -49.4004 -28.5 -55.7002l-83 -21.5c-5.39941 -1.39941 -10.8994 1.7998 -12.3994 7.10059l-22.9004 82.5996c-6.59961 24 8.7998 48.5996 34 52.5996c22 3.5 43.1006 -11.5996 49 -33l2.2998 -8.39941
|
||||
l8.40039 2.2002c21.5996 5.59961 45.0996 -5.10059 53.0996 -25.9004zM334 11.7002c17.7002 -64 10.9004 -39.5 13.4004 -46.7998c-30.5 -13.4004 -64 -20.9004 -99.4004 -20.9004c-137 0 -248 111 -248 248s111 248 248 248s248 -111 247.9 -248
|
||||
c0 -31.7998 -6.2002 -62.0996 -17.1006 -90c-6 1.5 -12.2002 2.7998 -18.5996 2.90039c-5.60059 9.69922 -13.6006 17.5 -22.6006 23.8994c6.7002 19.9004 10.4004 41.1006 10.4004 63.2002c0 110.3 -89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200
|
||||
c30.7998 0 59.9004 7.2002 86 19.7002z" />
|
||||
<glyph glyph-name="laugh" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM389.4 50.5996c37.7998 37.8008 58.5996 88 58.5996 141.4s-20.7998 103.6 -58.5996 141.4c-37.8008 37.7998 -88 58.5996 -141.4 58.5996s-103.6 -20.7998 -141.4 -58.5996
|
||||
c-37.7998 -37.8008 -58.5996 -88 -58.5996 -141.4s20.7998 -103.6 58.5996 -141.4c37.8008 -37.7998 88 -58.5996 141.4 -58.5996s103.6 20.7998 141.4 58.5996zM328 224c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM168 224
|
||||
c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM362.4 160c8.19922 0 14.5 -7 13.5 -15c-7.5 -59.2002 -58.9004 -105 -121.101 -105h-13.5996c-62.2002 0 -113.601 45.7998 -121.101 105c-1 8 5.30078 15 13.5 15h228.801z" />
|
||||
<glyph glyph-name="laugh-beam" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM389.4 50.5996c37.7998 37.8008 58.5996 88 58.5996 141.4s-20.7998 103.6 -58.5996 141.4c-37.8008 37.7998 -88 58.5996 -141.4 58.5996s-103.6 -20.7998 -141.4 -58.5996
|
||||
c-37.7998 -37.8008 -58.5996 -88 -58.5996 -141.4s20.7998 -103.6 58.5996 -141.4c37.8008 -37.7998 88 -58.5996 141.4 -58.5996s103.6 20.7998 141.4 58.5996zM328 296c23.7998 0 52.7002 -29.2998 55.7998 -71.4004c0.700195 -8.5 -10.7998 -11.8994 -14.8994 -4.5
|
||||
l-9.5 17c-7.7002 13.7002 -19.2002 21.6006 -31.5 21.6006c-12.3008 0 -23.8008 -7.90039 -31.5 -21.6006l-9.5 -17c-4.10059 -7.39941 -15.6006 -4.09961 -14.9004 4.5c3.2998 42.1006 32.2002 71.4004 56 71.4004zM127 220.1c-4.2002 -7.39941 -15.7002 -4 -15.0996 4.5
|
||||
c3.2998 42.1006 32.1992 71.4004 56 71.4004c23.7998 0 52.6992 -29.2998 56 -71.4004c0.699219 -8.5 -10.8008 -11.8994 -14.9004 -4.5l-9.5 17c-7.7002 13.7002 -19.2002 21.6006 -31.5 21.6006s-23.7998 -7.90039 -31.5 -21.6006zM362.4 160c8.19922 0 14.5 -7 13.5 -15
|
||||
c-7.5 -59.2002 -58.9004 -105 -121.101 -105h-13.5996c-62.2002 0 -113.601 45.7998 -121.101 105c-1 8 5.30078 15 13.5 15h228.801z" />
|
||||
<glyph glyph-name="laugh-squint" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM389.4 50.5996c37.7998 37.8008 58.5996 88 58.5996 141.4s-20.7998 103.6 -58.5996 141.4c-37.8008 37.7998 -88 58.5996 -141.4 58.5996s-103.6 -20.7998 -141.4 -58.5996
|
||||
c-37.7998 -37.8008 -58.5996 -88 -58.5996 -141.4s20.7998 -103.6 58.5996 -141.4c37.8008 -37.7998 88 -58.5996 141.4 -58.5996s103.6 20.7998 141.4 58.5996zM343.6 252l33.6006 -40.2998c8.59961 -10.4004 -3.90039 -24.7998 -15.4004 -18l-80 48
|
||||
c-7.7998 4.7002 -7.7998 15.8994 0 20.5996l80 48c11.6006 6.7998 24 -7.7002 15.4004 -18zM134.2 193.7c-11.6006 -6.7998 -24.1006 7.59961 -15.4004 18l33.6006 40.2998l-33.6006 40.2998c-8.59961 10.2998 3.7998 24.9004 15.4004 18l80 -48
|
||||
c7.7998 -4.7002 7.7998 -15.8994 0 -20.5996zM362.4 160c8.19922 0 14.5 -7 13.5 -15c-7.5 -59.2002 -58.9004 -105 -121.101 -105h-13.5996c-62.2002 0 -113.601 45.7998 -121.101 105c-1 8 5.30078 15 13.5 15h228.801z" />
|
||||
<glyph glyph-name="laugh-wink" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM389.4 50.5996c37.7998 37.8008 58.5996 88 58.5996 141.4s-20.7998 103.6 -58.5996 141.4c-37.8008 37.7998 -88 58.5996 -141.4 58.5996s-103.6 -20.7998 -141.4 -58.5996
|
||||
c-37.7998 -37.8008 -58.5996 -88 -58.5996 -141.4s20.7998 -103.6 58.5996 -141.4c37.8008 -37.7998 88 -58.5996 141.4 -58.5996s103.6 20.7998 141.4 58.5996zM328 284c25.7002 0 55.9004 -16.9004 59.7002 -42.0996c1.7998 -11.1006 -11.2998 -18.2002 -19.7998 -10.8008
|
||||
l-9.5 8.5c-14.8008 13.2002 -46.2002 13.2002 -61 0l-9.5 -8.5c-8.30078 -7.39941 -21.5 -0.399414 -19.8008 10.8008c4 25.1992 34.2002 42.0996 59.9004 42.0996zM168 224c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32z
|
||||
M362.4 160c8.19922 0 14.5 -7 13.5 -15c-7.5 -59.2002 -58.9004 -105 -121.101 -105h-13.5996c-62.2002 0 -113.601 45.7998 -121.101 105c-1 8 5.30078 15 13.5 15h228.801z" />
|
||||
<glyph glyph-name="meh-blank" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM168 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32
|
||||
s-32 14.2998 -32 32s14.2998 32 32 32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32z" />
|
||||
<glyph glyph-name="meh-rolling-eyes" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM336 296c39.7998 0 72 -32.2002 72 -72s-32.2002 -72 -72 -72
|
||||
s-72 32.2002 -72 72s32.2002 72 72 72zM336 184c22.0996 0 40 17.9004 40 40c0 13.5996 -7.2998 25.0996 -17.7002 32.2998c1 -2.59961 1.7002 -5.39941 1.7002 -8.2998c0 -13.2998 -10.7002 -24 -24 -24s-24 10.7002 -24 24c0 3 0.700195 5.7002 1.7002 8.2998
|
||||
c-10.4004 -7.2002 -17.7002 -18.7002 -17.7002 -32.2998c0 -22.0996 17.9004 -40 40 -40zM232 224c0 -39.7998 -32.2002 -72 -72 -72s-72 32.2002 -72 72s32.2002 72 72 72s72 -32.2002 72 -72zM120 224c0 -22.0996 17.9004 -40 40 -40s40 17.9004 40 40
|
||||
c0 13.5996 -7.2998 25.0996 -17.7002 32.2998c1 -2.59961 1.7002 -5.39941 1.7002 -8.2998c0 -13.2998 -10.7002 -24 -24 -24s-24 10.7002 -24 24c0 3 0.700195 5.7002 1.7002 8.2998c-10.4004 -7.2002 -17.7002 -18.7002 -17.7002 -32.2998zM312 96
|
||||
c13.2002 0 24 -10.7998 24 -24s-10.7998 -24 -24 -24h-128c-13.2002 0 -24 10.7998 -24 24s10.7998 24 24 24h128z" />
|
||||
<glyph glyph-name="sad-cry" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM392 53.5996c34.5996 35.9004 56 84.7002 56 138.4c0 110.3 -89.7002 200 -200 200s-200 -89.7002 -200 -200c0 -53.7002 21.4004 -102.4 56 -138.4v114.4
|
||||
c0 13.2002 10.7998 24 24 24s24 -10.7998 24 -24v-151.4c28.5 -15.5996 61.2002 -24.5996 96 -24.5996s67.5 9 96 24.5996v151.4c0 13.2002 10.7998 24 24 24s24 -10.7998 24 -24v-114.4zM205.8 213.5c-5.7998 -3.2002 -11.2002 -0.700195 -13.7002 1.59961l-9.5 8.5
|
||||
c-14.7998 13.2002 -46.1992 13.2002 -61 0l-9.5 -8.5c-3.7998 -3.39941 -9.2998 -4 -13.6992 -1.59961c-4.40039 2.40039 -6.90039 7.40039 -6.10059 12.4004c3.90039 25.1992 34.2002 42.0996 59.7998 42.0996c25.6006 0 55.8008 -16.9004 59.8008 -42.0996
|
||||
c0.799805 -5 -1.7002 -10 -6.10059 -12.4004zM344 268c25.7002 0 55.9004 -16.9004 59.7998 -42.0996c0.799805 -5 -1.7002 -10 -6.09961 -12.4004c-5.7002 -3.09961 -11.2002 -0.599609 -13.7002 1.59961l-9.5 8.5c-14.7998 13.2002 -46.2002 13.2002 -61 0l-9.5 -8.5
|
||||
c-3.7998 -3.39941 -9.2002 -4 -13.7002 -1.59961c-4.39941 2.40039 -6.89941 7.40039 -6.09961 12.4004c3.89941 25.1992 34.0996 42.0996 59.7998 42.0996zM248 176c30.9004 0 56 -28.7002 56 -64s-25.0996 -64 -56 -64s-56 28.7002 -56 64s25.0996 64 56 64z" />
|
||||
<glyph glyph-name="sad-tear" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM256 144c38.0996 0 74 -16.7998 98.5 -46.0996
|
||||
c8.5 -10.2002 7.09961 -25.3008 -3.09961 -33.8008c-10.6006 -8.7998 -25.7002 -6.69922 -33.8008 3.10059c-15.2998 18.2998 -37.7998 28.7998 -61.5996 28.7998c-13.2002 0 -24 10.7998 -24 24s10.7998 24 24 24zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32
|
||||
s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM162.4 173.2c2.7998 3.7002 8.39941 3.7002 11.1992 0c11.4004 -15.2998 36.4004 -50.6006 36.4004 -68.1006
|
||||
c0 -22.6992 -18.7998 -41.0996 -42 -41.0996s-42 18.4004 -42 41.0996c0 17.5 25 52.8008 36.4004 68.1006z" />
|
||||
<glyph glyph-name="smile-beam" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM332 135.4c8.5 10.1992 23.5996 11.5 33.7998 3.09961
|
||||
c10.2002 -8.5 11.6006 -23.5996 3.10059 -33.7998c-30 -36 -74.1006 -56.6006 -120.9 -56.6006s-90.9004 20.6006 -120.9 56.6006c-8.39941 10.2002 -7.09961 25.2998 3.10059 33.7998c10.2002 8.40039 25.2998 7.09961 33.7998 -3.09961
|
||||
c20.7998 -25.1006 51.5 -39.4004 84 -39.4004s63.2002 14.4004 84 39.4004zM136.5 237l-9.5 -17c-1.90039 -3.2002 -5.90039 -4.7998 -9.2998 -3.7002c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004
|
||||
c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998c-3.09961 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996s-23.7998 -7.89941 -31.5 -21.5996zM328 296c23.7998 0 52.7002 -29.2998 56 -71.4004
|
||||
c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998c-3.09961 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996s-23.7998 -7.89941 -31.5 -21.5996l-9.5 -17c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002
|
||||
c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004z" />
|
||||
<glyph glyph-name="surprise" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM248 168c35.2998 0 64 -28.7002 64 -64s-28.7002 -64 -64 -64
|
||||
s-64 28.7002 -64 64s28.7002 64 64 64zM200 240c0 -17.7002 -14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32z" />
|
||||
<glyph glyph-name="tired" unicode="" horiz-adv-x="496"
|
||||
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM377.1 295.8c3.80078 -4.39941 3.90039 -11 0.100586 -15.5
|
||||
l-33.6006 -40.2998l33.6006 -40.2998c3.7998 -4.5 3.7002 -11 -0.100586 -15.5c-3.5 -4.10059 -9.89941 -5.7002 -15.2998 -2.5l-80 48c-3.59961 2.2002 -5.7998 6.09961 -5.7998 10.2998s2.2002 8.09961 5.7998 10.2998l80 48c5 2.90039 11.5 1.90039 15.2998 -2.5z
|
||||
M220 240c0 -4.2002 -2.2002 -8.09961 -5.7998 -10.2998l-80 -48c-5.40039 -3.2002 -11.7998 -1.60059 -15.2998 2.5c-3.80078 4.5 -3.90039 11 -0.100586 15.5l33.6006 40.2998l-33.6006 40.2998c-3.7998 4.5 -3.7002 11 0.100586 15.5
|
||||
c3.7998 4.40039 10.2998 5.5 15.2998 2.5l80 -48c3.59961 -2.2002 5.7998 -6.09961 5.7998 -10.2998zM248 176c45.4004 0 100.9 -38.2998 107.8 -93.2998c1.5 -11.9004 -7 -21.6006 -15.5 -17.9004c-22.7002 9.7002 -56.2998 15.2002 -92.2998 15.2002
|
||||
s-69.5996 -5.5 -92.2998 -15.2002c-8.60059 -3.7002 -17 6.10059 -15.5 17.9004c6.89941 55 62.3994 93.2998 107.8 93.2998z" />
|
||||
</font>
|
||||
</defs></svg>
|
||||
|
Before Width: | Height: | Size: 141 KiB |
|
Before Width: | Height: | Size: 898 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 729 KiB |
|
Before Width: | Height: | Size: 113 KiB |
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"name": "TSUN-Proxy",
|
||||
"short_name": "Proxy",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/web-app-manifest-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
},
|
||||
{
|
||||
"src": "/web-app-manifest-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
}
|
||||
|
Before Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 189 KiB |
@@ -1,155 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{lang}}" >
|
||||
<head>
|
||||
<title>{% block title %}{% endblock title %}</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename= 'css/style.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename= 'font-awesome/css/all.min.css') }}">
|
||||
<link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<link rel="shortcut icon" href="/favicon.ico" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: Roboto;
|
||||
src: url("{{ url_for('static', filename= 'font/roboto-light.ttf') }}");
|
||||
}
|
||||
html,body,h1,h2,h3,h4,h5 {font-family: Roboto, sans-serif}
|
||||
</style>
|
||||
</head>
|
||||
<body class="w3-light-grey">
|
||||
|
||||
<!-- Top container -->
|
||||
<div class="w3-bar w3-dark-grey w3-large" style="z-index:4">
|
||||
<button class="w3-bar-item w3-button w3-hide-large" onclick="w3_open();"><i class="fa fa-bars"></i> Menu</button>
|
||||
<div class="w3-dropdown-hover w3-right">
|
||||
<button class="w3-button">{{lang_str}}</button>
|
||||
<div class="w3-dropdown-content w3-bar-block w3-card-4" style="right:0">
|
||||
{% for language in languages %}
|
||||
<a href="{{url_for('web.set_language', language=language)}}" class="w3-bar-item w3-button">{{languages[language]}}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if fetch_url is defined %}
|
||||
<button class="w3-bar-item w3-button w3-right" onclick="fetch_data();"><span class="w3-hide-small">{{_('Updated:')}} </span><span id="update-time"></span> <i class="w3-hover fa fa-rotate-right w3-medium"></i></button>
|
||||
{% endif %}
|
||||
<div class="w3-clear"></div>
|
||||
</div>
|
||||
|
||||
<!-- Sidebar/menu -->
|
||||
<nav class="w3-sidebar w3-collapse w3-white" style="z-index:3;width:250px;" id="mySidebar"><br>
|
||||
<div class="w3-container w3-cell-row">
|
||||
<div class="w3-cell w3-cell-middle">
|
||||
<img src="{{url_for('static', filename= 'images/favicon.svg') }}" alt="" class="w3-circle w3-margin-right" style="width:60px">
|
||||
</div>
|
||||
<div class="w3-cell">
|
||||
<span><b class="w3-xlarge">TSUN-Proxy</b><br>{{_('Version:')}} {{version}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="w3-container">
|
||||
<h5>Dashboard</h5>
|
||||
</div>
|
||||
<div class="w3-bar-block">
|
||||
<button href="#" class="w3-bar-item w3-button w3-padding-16 w3-hide-large w3-dark-grey w3-hover-black" onclick="w3_close()" title="close menu"><i class="fa fa-remove fa-fw"></i> Close Menu</button>
|
||||
<a href="{{ url_for('.index')}}" class="w3-bar-item w3-button w3-padding {% block menu1_class %}{% endblock %}"><i class="fa fa-network-wired fa-fw"></i> {{_('Connections')}}</a>
|
||||
<a href="{{ url_for('.mqtt')}}" class="w3-bar-item w3-button w3-padding {% block menu2_class %}{% endblock %}"><i class="fa fa-database fa-fw"></i> MQTT</a>
|
||||
<a href="{{ url_for('.notes')}}" class="w3-bar-item w3-button w3-padding {% block menu3_class %}{% endblock %}"><i class="fa fa-info fa-fw"></i> {{_('Important Messages')}}</a>
|
||||
<a href="{{ url_for('.logging')}}" class="w3-bar-item w3-button w3-padding {% block menu4_class %}{% endblock %}"><i class="fa fa-file-export fa-fw"></i> {{_('Log Files')}}</a>
|
||||
{% if hassio is defined %}
|
||||
<br>
|
||||
<a href="/hassio/addon/{{addonname}}/config" target="_top" class="w3-bar-item w3-button w3-padding"><i class="fa fa-gear fa-fw"></i> {{_('Add-on Config')}}</a>
|
||||
<a href="/hassio/addon/{{addonname}}/logs" target="_top" class="w3-bar-item w3-button w3-padding"><i class="fa fa-file fa-fw"></i> {{_('Add-on Log')}}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
|
||||
<!-- Overlay effect when opening sidebar on small screens -->
|
||||
<button class="w3-overlay w3-hide-large w3-animate-opacity" onclick="w3_close()" style="cursor:pointer" title="close side menu" id="myOverlay"></button>
|
||||
|
||||
<!-- !PAGE CONTENT! -->
|
||||
<div class="w3-main" style="margin-left:250px;margin-top:43px;">
|
||||
|
||||
<!-- Header -->
|
||||
{% block header %}
|
||||
<header class="w3-container" style="padding-top:22px">
|
||||
<h5><b>{% block headline %}{% endblock headline %}</b></h5>
|
||||
</header>
|
||||
{% endblock header %}
|
||||
|
||||
{% block content %} {% endblock content%}
|
||||
|
||||
<!-- Footer -->
|
||||
{% block footer %}
|
||||
<footer class="w3-container w3-padding-16 w3-light-grey">
|
||||
<h4>FOOTER</h4>
|
||||
<p>Powered by <a href="https://www.w3schools.com/w3css/default.asp" target="_blank">w3.css</a></p>
|
||||
</footer>
|
||||
{% endblock footer %}
|
||||
|
||||
<!-- End page content -->
|
||||
</div>
|
||||
|
||||
{% block trailer %}
|
||||
<script>
|
||||
// Get the Sidebar
|
||||
var mySidebar = document.getElementById("mySidebar");
|
||||
|
||||
// Get the DIV with overlay effect
|
||||
var overlayBg = document.getElementById("myOverlay");
|
||||
|
||||
// Toggle between showing and hiding the sidebar, and add overlay effect
|
||||
function w3_open() {
|
||||
if (mySidebar.style.display === 'block') {
|
||||
mySidebar.style.display = 'none';
|
||||
overlayBg.style.display = "none";
|
||||
} else {
|
||||
mySidebar.style.display = 'block';
|
||||
overlayBg.style.display = "block";
|
||||
}
|
||||
}
|
||||
|
||||
// Close the sidebar with the close button
|
||||
function w3_close() {
|
||||
mySidebar.style.display = "none";
|
||||
overlayBg.style.display = "none";
|
||||
}
|
||||
{% if fetch_url is defined %}
|
||||
function fetch_data() {
|
||||
fetch("{{fetch_url}}")
|
||||
.then(response => response.json())
|
||||
.then(function (data) {
|
||||
Object.keys(data).forEach(key => {
|
||||
//console.log(`${key}: ${data[key]}`);
|
||||
try {
|
||||
elm = document.getElementById(key)
|
||||
elm.innerHTML = data[key]
|
||||
}
|
||||
catch(err) {
|
||||
console.log('error: ' + err + ' (for key: ' + key + ')');
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.log('error: ' + err);
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('load', function () {
|
||||
// Your document is loaded.
|
||||
var fetchInterval = 5000; // 5 seconds.
|
||||
fetch_data()
|
||||
// Invoke the request every 5 seconds.
|
||||
setInterval(fetch_data, fetchInterval);
|
||||
});
|
||||
{% endif %}
|
||||
|
||||
</script>
|
||||
{% endblock trailer %}
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,67 +0,0 @@
|
||||
{% extends 'base.html.j2' %}
|
||||
|
||||
{% block title %}{{_("TSUN Proxy - Connections")}}{% endblock title %}
|
||||
{% block menu1_class %}w3-blue{% endblock %}
|
||||
{% block headline %}<i class="fa fa-network-wired"></i> {{_('Proxy Connection Overview')}}{% endblock headline %}
|
||||
|
||||
{% block content %}
|
||||
<div class="w3-row-padding w3-margin-bottom">
|
||||
<div class="w3-quarter">
|
||||
<div class="w3-card-4">
|
||||
<div class="w3-container w3-indigo w3-padding-16">
|
||||
<div class="w3-left"><i class="fa fa-upload w3-xxxlarge fa-rotate-180"></i></div>
|
||||
<div id = "server-cnt" class="w3-right">
|
||||
<h3>-</h3>
|
||||
</div>
|
||||
<div class="w3-clear"></div>
|
||||
<h4>{{_('Server Mode')}}</h4>
|
||||
<div class="w3-hide-small w3-hide-medium" style="min-height:50px">{{_('Established from device to proxy')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w3-quarter">
|
||||
<div class="w3-card-4">
|
||||
<div class="w3-container w3-purple w3-padding-16">
|
||||
<div class="w3-left"><i class="fa fa-download w3-xxxlarge fa-rotate-180"></i></div>
|
||||
<div id = "client-cnt" class="w3-right">
|
||||
<h3>-</h3>
|
||||
</div>
|
||||
<div class="w3-clear"></div>
|
||||
<h4>{{_('Client Mode')}}</h4>
|
||||
<div class="w3-hide-small w3-hide-medium" style="min-height:50px">{{_('Established from proxy to device')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w3-quarter">
|
||||
<div class="w3-card-4">
|
||||
<div class="w3-container w3-orange w3-text-white w3-padding-16">
|
||||
<div class="w3-left"><i class="fa fa-cloud w3-xxxlarge"></i></div>
|
||||
<div id = "proxy-cnt" class="w3-right">
|
||||
<h3>-</h3>
|
||||
</div>
|
||||
<div class="w3-clear"></div>
|
||||
<h4>{{_('Proxy Mode')}}</h4>
|
||||
<div class="w3-hide-small w3-hide-medium" style="min-height:50px">{{_('Forwarding data to cloud')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w3-quarter">
|
||||
<div class="w3-card-4">
|
||||
<div class="w3-container w3-teal w3-padding-16">
|
||||
<div class="w3-left"><i class="fa fa-cloud-arrow-up-alt w3-xxxlarge"></i></div>
|
||||
<div id = "emulation-cnt" class="w3-right">
|
||||
<h3>-</h3>
|
||||
</div>
|
||||
<div class="w3-clear"></div>
|
||||
<h4>{{_('Emu Mode')}}</h4>
|
||||
<div class="w3-hide-small w3-hide-medium" style="min-height:50px">{{_('Emulation sends data to cloud')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="notes-list"></div>
|
||||
<div id="conn-table"></div>
|
||||
{% endblock content%}
|
||||
|
||||
{% block footer %}{% endblock footer %}
|
||||
@@ -1,30 +0,0 @@
|
||||
{% extends 'base.html.j2' %}
|
||||
|
||||
{% block title %}{{_("TSUN Proxy - Log Files")}}{% endblock title %}
|
||||
{% block menu4_class %}w3-blue{% endblock %}
|
||||
{% block headline %}<i class="fa fa-file-export fa-fw"></i> {{_('Log Files')}}{% endblock headline %}
|
||||
{% block content %}
|
||||
<div id="id01" class="w3-modal">
|
||||
<div class="w3-modal-content" style="width:600px">
|
||||
<div class="w3-container w3-padding-24">
|
||||
<h2>{{_('Do you really want to delete the log file: <br>%(file)s ?', file='<b><span id="id03"></span></b>')}}</h2>
|
||||
<div class="w3-bar">
|
||||
<button id="id02" class="w3-button w3-red" onclick="deleteFile(); document.getElementById('id01').style.display='none'">{{_('Delete File')}}</button>
|
||||
<button class="w3-button w3-grey w3-right" onclick="document.getElementById('id01').style.display='none'">{{_('Abort')}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="file-list"></div>
|
||||
|
||||
<script>
|
||||
function deleteFile() {
|
||||
fname = document.getElementById('id02').href;
|
||||
fetch(fname, {method: 'DELETE'})
|
||||
.then(fetch_data())
|
||||
}
|
||||
</script>
|
||||
{% endblock content%}
|
||||
|
||||
{% block footer %}{% endblock footer %}
|
||||
@@ -1,52 +0,0 @@
|
||||
{% extends 'base.html.j2' %}
|
||||
|
||||
{% block title %}{{_("TSUN Proxy - MQTT Status")}}{% endblock title %}
|
||||
{% block menu2_class %}w3-blue{% endblock %}
|
||||
{% block headline %}<i class="fa fa-database"></i> {{_('MQTT Overview')}}{% endblock headline %}
|
||||
{% block content %}
|
||||
<div class="w3-row-padding w3-margin-bottom">
|
||||
<div class="w3-third">
|
||||
<div class="w3-card-4">
|
||||
<div class="w3-container w3-indigo w3-padding-16">
|
||||
<div class="w3-left"><i class="fa fa-business-time w3-xxxlarge"></i></div>
|
||||
<div id = "mqtt-ctime" class="w3-right">
|
||||
<h3>-</h3>
|
||||
</div>
|
||||
<div class="w3-clear"></div>
|
||||
<h4>{{_('Connection Time')}}</h4>
|
||||
<div class="w3-hide-small w3-hide-medium" style="min-height:50px">{{_('Time at which the connection was established')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w3-third">
|
||||
<div class="w3-card-4">
|
||||
<div class="w3-container w3-purple w3-padding-16">
|
||||
<div class="w3-left"><i class="fa fa-angle-double-right w3-xxxlarge"></i></div>
|
||||
<div id = "mqtt-tx" class="w3-right">
|
||||
<h3>-</h3>
|
||||
</div>
|
||||
<div class="w3-clear"></div>
|
||||
<h4>{{_('Published Topics')}}</h4>
|
||||
<div class="w3-hide-small w3-hide-medium" style="min-height:50px">{{_('Number of published topics')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w3-third">
|
||||
<div class="w3-card-4">
|
||||
<div class="w3-container w3-orange w3-text-white w3-padding-16">
|
||||
<div class="w3-left"><i class="fa fa-angle-double-left w3-xxxlarge"></i></div>
|
||||
<div id = "mqtt-rx" class="w3-right">
|
||||
<h3>-</h3>
|
||||
</div>
|
||||
<div class="w3-clear"></div>
|
||||
<h4>{{_('Received Topics')}}</h4>
|
||||
<div class="w3-hide-small w3-hide-medium" style="min-height:50px">{{_('Number of topics received')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="notes-list"></div>
|
||||
<div id="mqtt-table"></div>
|
||||
{% endblock content%}
|
||||
|
||||
{% block footer %}{% endblock footer %}
|
||||
@@ -1,10 +0,0 @@
|
||||
{% extends 'base.html.j2' %}
|
||||
|
||||
{% block title %}{{_("TSUN Proxy - Important Messages")}}{% endblock title %}
|
||||
{% block menu3_class %}w3-blue{% endblock %}
|
||||
{% block headline %}<i class="fa fa-info fa-fw"></i> {{_('Important Messages')}}{% endblock headline %}
|
||||
{% block content %}
|
||||
<div id="notes-list"></div>
|
||||
{% endblock content%}
|
||||
|
||||
{% block footer %}{% endblock footer %}
|
||||
@@ -1,33 +0,0 @@
|
||||
<div class="w3-row-padding w3-margin-bottom">
|
||||
{% for file in dir_list %}
|
||||
<div class="w3-quarter w3-margin-bottom">
|
||||
|
||||
<div class="w3-card-4">
|
||||
<header class="w3-container w3-teal" style="min-height:80px">
|
||||
<h4>{{file.name}}</h4>
|
||||
</header>
|
||||
|
||||
<table class="w3-table">
|
||||
{% for idx, name in [('created',_('Created')), ('modified', _('Modified')), ('size', _('Size'))]%}
|
||||
<tr>
|
||||
<td>{{_(name)}}:</td>
|
||||
<td>{{file[idx]}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
<footer class="w3-teal">
|
||||
<a href="{{ url_for('.send',file=file.name)}}" class="w3-button w3-hover-teal w3-hover-text-black"><i class="fa fa-file-download"></i> {{_('Download File')}}</a>
|
||||
<a class="w3-button w3-right w3-hover-teal w3-hover-text-black"
|
||||
onclick="document.getElementById('id03').innerHTML='{{file.name}}'; document.getElementById('id02').href='{{ url_for('.delete',file=file.name)}}'; document.getElementById('id01').style.display='block';"><i class="fa fa-trash"></i></a>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% if 0 == (loop.index%4) and not last %}
|
||||
</div>
|
||||
<div class="w3-row-padding w3-margin-bottom">
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
{% if notes|length > 0 %}
|
||||
<div class="w3-container w3-margin-bottom">
|
||||
<h5>{{_("Warnings and error messages")}} </h5>
|
||||
<ul class="w3-ul w3-card-4">
|
||||
{% for note in notes %}
|
||||
<li class="{% if note.level is le(30) %}w3-leftbar w3-rightbar w3-pale-blue w3-border-blue{% else %}w3-leftbar w3-rightbar w3-pale-red w3-border-red{% endif %}">
|
||||
<span class="w3-col" style="width:150px">{{note.ctime|datetimeformat(format='short')}}</span>
|
||||
<span class="w3-col w3-hide-small" style="width:100px">{{note.lname|e}}</span>
|
||||
<span class="w3-rest">{{note.msg|e}}</span>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% elif not hide_if_empty %}
|
||||
<div class="w3-container w3-margin-bottom">
|
||||
<div class="w3-leftbar w3-rightbar w3-pale-green w3-border-green">
|
||||
<div class="w3-container">
|
||||
<h2>{{_("Well done!")}}</h2>
|
||||
<p>{{_("No warnings or errors have been logged since the last proxy start.")}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -1,42 +0,0 @@
|
||||
{% macro table_elm(elm, col_class, tag='td') -%}
|
||||
{% if elm is mapping %}
|
||||
<{{tag}}
|
||||
{% if (col_class|length) > 0 or elm.class is defined%}class="{{col_class}} {{elm.class}}"{% endif %}
|
||||
{% if elm.colspan is defined %}colspan="{{elm.colspan}}"{% endif %}
|
||||
{% if elm.rowspan is defined %}rowspan="{{elm.rowspan}}"{% endif %}
|
||||
>{{elm.val}}</{{tag}}>
|
||||
{% else %}
|
||||
<{{tag}}
|
||||
{% if (col_class|length) > 0 %}class="{{col_class}}"{% endif %}
|
||||
>{{elm}}</{{tag}}>
|
||||
{% endif %}
|
||||
{%- endmacro%}
|
||||
|
||||
<div class="w3-container w3-margin-bottom">
|
||||
<h5>{{table.headline}}</h5>
|
||||
<div class="w3-card-4">
|
||||
|
||||
<table class="w3-table w3-bordered w3-hoverable w3-white">
|
||||
{% if table.thead is defined%}
|
||||
<thead>
|
||||
{% for row in table.thead %}
|
||||
<tr>
|
||||
{% for col in row %}
|
||||
{{table_elm(col, table.col_classes[loop.index0], 'th')}}
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</thead>
|
||||
{% endif %}
|
||||
<tbody>
|
||||
{% for row in table.tbody %}
|
||||
<tr>
|
||||
{% for col in row %}
|
||||
{{table_elm(col, table.col_classes[loop.index0])}}
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,26 +0,0 @@
|
||||
from quart import url_for as quart_url_for
|
||||
from . import web
|
||||
|
||||
|
||||
def url_for(*args, **kwargs):
|
||||
"""Return the url for a specific endpoint.
|
||||
|
||||
This wrapper optionally convert into a relative url.
|
||||
|
||||
This is most useful in templates and redirects to create a URL
|
||||
that can be used in the browser.
|
||||
|
||||
Arguments:
|
||||
endpoint: The endpoint to build a url for, if prefixed with
|
||||
``.`` it targets endpoint's in the current blueprint.
|
||||
_anchor: Additional anchor text to append (i.e. #text).
|
||||
_external: Return an absolute url for external (to app) usage.
|
||||
_method: The method to consider alongside the endpoint.
|
||||
_scheme: A specific scheme to use.
|
||||
values: The values to build into the URL, as specified in
|
||||
the endpoint rule.
|
||||
"""
|
||||
url = quart_url_for(*args, **kwargs)
|
||||
if '/' == url[0] and web.build_relative_urls:
|
||||
url = '.' + url
|
||||
return url
|
||||
@@ -1 +0,0 @@
|
||||
mqtt.port = ":1883"
|
||||
@@ -1,20 +0,0 @@
|
||||
import pytest_asyncio
|
||||
import asyncio
|
||||
|
||||
|
||||
@pytest_asyncio.fixture
|
||||
async def my_loop():
|
||||
event_loop = asyncio.get_running_loop()
|
||||
yield event_loop
|
||||
|
||||
# Collect all tasks and cancel those that are not 'done'.
|
||||
tasks = asyncio.all_tasks(event_loop)
|
||||
tasks = [t for t in tasks if not t.done()]
|
||||
for task in tasks:
|
||||
task.cancel()
|
||||
|
||||
# Wait for all tasks to complete, ignoring any CancelledErrors
|
||||
try:
|
||||
await asyncio.wait(tasks)
|
||||
except asyncio.exceptions.CancelledError:
|
||||
pass
|
||||
@@ -1,19 +0,0 @@
|
||||
2025-04-30 00:01:23 INFO | root | Server "proxy - unknown" will be started
|
||||
2025-04-30 00:01:24 INFO | root | current dir: /Users/sallius/tsun/tsun-gen3-proxy
|
||||
2025-04-30 00:01:25 INFO | root | config_path: ./config/
|
||||
2025-04-30 00:01:26 INFO | root | json_config: None
|
||||
2025-04-30 00:01:27 INFO | root | toml_config: None
|
||||
2025-04-30 00:01:28 INFO | root | trans_path: ../translations/
|
||||
2025-04-30 00:01:29 INFO | root | rel_urls: False
|
||||
2025-04-30 00:01:30 INFO | root | log_path: ./log/
|
||||
2025-04-30 00:01:31 INFO | root | log_backups: unlimited
|
||||
2025-04-30 00:01:32 INFO | root | LOG_LVL : None
|
||||
2025-04-30 00:01:33 INFO | root | ******
|
||||
2025-04-30 00:01:34 INFO | root | Read from /Users/sallius/tsun/tsun-gen3-proxy/app/src/cnf/default_config.toml => ok
|
||||
2025-04-30 00:01:35 INFO | root | Read from environment => ok
|
||||
2025-04-30 00:01:36 INFO | root | Read from ./config/config.json => n/a
|
||||
2025-04-30 00:01:37 INFO | root | Read from ./config/config.toml => n/a
|
||||
2025-04-30 00:01:38 INFO | root | ******
|
||||
2025-04-30 00:01:39 INFO | root | listen on port: 5005 for inverters
|
||||
2025-04-30 00:01:40 INFO | root | listen on port: 10000 for inverters
|
||||
2025-04-30 00:01:41 INFO | root | Start Quart
|
||||
@@ -8,7 +8,6 @@ from infos import Infos
|
||||
from inverter_base import InverterBase
|
||||
from async_stream import AsyncStreamServer, AsyncStreamClient, StreamPtr
|
||||
from messages import Message
|
||||
from mock import patch, call
|
||||
|
||||
from test_modbus_tcp import FakeReader, FakeWriter
|
||||
from test_inverter_base import config_conn, patch_open_connection
|
||||
@@ -75,13 +74,6 @@ def test_health():
|
||||
cnt += 1
|
||||
assert cnt == 0
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def spy_inc_cnt():
|
||||
with patch.object(Infos, 'inc_counter', wraps=Infos.inc_counter) as infos:
|
||||
yield infos
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_close_cb():
|
||||
assert asyncio.get_running_loop()
|
||||
@@ -92,10 +84,7 @@ async def test_close_cb():
|
||||
return 0.1
|
||||
def closed():
|
||||
nonlocal cnt
|
||||
# The callback will be called after the AsyncStreamServer
|
||||
# constructer has finished and so ifc must be defined in the
|
||||
# upper scope
|
||||
assert "ifc" in locals()
|
||||
nonlocal ifc
|
||||
ifc.close() # clears the closed callback
|
||||
cnt += 1
|
||||
|
||||
@@ -124,6 +113,7 @@ async def test_close_cb():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_read():
|
||||
global test
|
||||
assert asyncio.get_running_loop()
|
||||
reader = FakeReader()
|
||||
reader.test = FakeReader.RD_TEST_13_BYTES
|
||||
@@ -134,13 +124,11 @@ async def test_read():
|
||||
return 1
|
||||
def closed():
|
||||
nonlocal cnt
|
||||
# The callback will be called after the AsyncStreamServer
|
||||
# constructer has finished and so ifc must be defined in the
|
||||
# upper scope
|
||||
assert "ifc" in locals()
|
||||
nonlocal ifc
|
||||
ifc.close() # clears the closed callback
|
||||
cnt += 1
|
||||
def app_read():
|
||||
nonlocal ifc
|
||||
ifc.proc_start -= 3
|
||||
return 0.01 # async wait of 0.01
|
||||
cnt = 0
|
||||
@@ -163,6 +151,7 @@ async def test_read():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_write():
|
||||
global test
|
||||
assert asyncio.get_running_loop()
|
||||
reader = FakeReader()
|
||||
reader.test = FakeReader.RD_TEST_13_BYTES
|
||||
@@ -173,13 +162,11 @@ async def test_write():
|
||||
return 1
|
||||
def closed():
|
||||
nonlocal cnt
|
||||
# The callback will be called after the AsyncStreamServer
|
||||
# constructer has finished and so ifc must be defined in the
|
||||
# upper scope
|
||||
assert "ifc" in locals()
|
||||
nonlocal ifc
|
||||
ifc.close() # clears the closed callback
|
||||
cnt += 1
|
||||
def app_read():
|
||||
nonlocal ifc
|
||||
ifc.proc_start -= 3
|
||||
return 0.01 # async wait of 0.01
|
||||
|
||||
@@ -216,6 +203,7 @@ async def test_publ_mqtt_cb():
|
||||
return 0.1
|
||||
async def publ_mqtt():
|
||||
nonlocal cnt
|
||||
nonlocal ifc
|
||||
cnt += 1
|
||||
|
||||
cnt = 0
|
||||
@@ -245,10 +233,7 @@ async def test_create_remote_cb():
|
||||
return 0.1
|
||||
async def create_remote():
|
||||
nonlocal cnt
|
||||
# The callback will be called after the AsyncStreamServer
|
||||
# constructer has finished and so ifc must be defined in the
|
||||
# upper scope
|
||||
assert "ifc" in locals()
|
||||
nonlocal ifc
|
||||
ifc.close() # clears the closed callback
|
||||
cnt += 1
|
||||
|
||||
@@ -270,6 +255,7 @@ async def test_create_remote_cb():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sw_exception():
|
||||
global test
|
||||
assert asyncio.get_running_loop()
|
||||
reader = FakeReader()
|
||||
reader.test = FakeReader.RD_TEST_SW_EXCEPT
|
||||
@@ -280,10 +266,7 @@ async def test_sw_exception():
|
||||
return 1
|
||||
def closed():
|
||||
nonlocal cnt
|
||||
# The callback will be called after the AsyncStreamServer
|
||||
# constructer has finished and so ifc must be defined in the
|
||||
# upper scope
|
||||
assert "ifc" in locals()
|
||||
nonlocal ifc
|
||||
ifc.close() # clears the closed callback
|
||||
cnt += 1
|
||||
cnt = 0
|
||||
@@ -302,6 +285,7 @@ async def test_sw_exception():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_os_error():
|
||||
global test
|
||||
assert asyncio.get_running_loop()
|
||||
reader = FakeReader()
|
||||
reader.test = FakeReader.RD_TEST_OS_ERROR
|
||||
@@ -309,11 +293,12 @@ async def test_os_error():
|
||||
reader.on_recv.set()
|
||||
writer = FakeWriter()
|
||||
cnt = 0
|
||||
|
||||
def timeout():
|
||||
return 1
|
||||
def closed():
|
||||
nonlocal cnt
|
||||
nonlocal ifc
|
||||
ifc.close() # clears the closed callback
|
||||
cnt += 1
|
||||
cnt = 0
|
||||
ifc = AsyncStreamClient(reader, writer, None, closed)
|
||||
@@ -376,13 +361,10 @@ async def test_forward():
|
||||
assert asyncio.get_running_loop()
|
||||
remote = StreamPtr(None)
|
||||
cnt = 0
|
||||
|
||||
async def _create_remote():
|
||||
nonlocal cnt
|
||||
nonlocal cnt, remote, ifc
|
||||
create_remote(remote, TestType.FWD_NO_EXCPT)
|
||||
# The callback will be called after the AsyncStreamServer
|
||||
# constructer has finished and so ifc must be defined in the
|
||||
# upper scope
|
||||
assert "ifc" in locals()
|
||||
ifc.fwd_add(b'test-forward_msg2 ')
|
||||
cnt += 1
|
||||
|
||||
@@ -400,7 +382,7 @@ async def test_forward_with_conn():
|
||||
cnt = 0
|
||||
|
||||
async def _create_remote():
|
||||
nonlocal cnt
|
||||
nonlocal cnt, remote, ifc
|
||||
cnt += 1
|
||||
|
||||
cnt = 0
|
||||
@@ -435,7 +417,7 @@ async def test_forward_sw_except():
|
||||
cnt = 0
|
||||
|
||||
async def _create_remote():
|
||||
nonlocal cnt
|
||||
nonlocal cnt, remote
|
||||
create_remote(remote, TestType.FWD_SW_EXCPT)
|
||||
cnt += 1
|
||||
|
||||
@@ -453,7 +435,7 @@ async def test_forward_os_error():
|
||||
cnt = 0
|
||||
|
||||
async def _create_remote():
|
||||
nonlocal cnt
|
||||
nonlocal cnt, remote
|
||||
create_remote(remote, TestType.FWD_OS_ERROR)
|
||||
cnt += 1
|
||||
|
||||
@@ -471,7 +453,7 @@ async def test_forward_os_error2():
|
||||
cnt = 0
|
||||
|
||||
async def _create_remote():
|
||||
nonlocal cnt
|
||||
nonlocal cnt, remote
|
||||
create_remote(remote, TestType.FWD_OS_ERROR, True)
|
||||
cnt += 1
|
||||
|
||||
@@ -489,7 +471,7 @@ async def test_forward_os_error3():
|
||||
cnt = 0
|
||||
|
||||
async def _create_remote():
|
||||
nonlocal cnt
|
||||
nonlocal cnt, remote
|
||||
create_remote(remote, TestType.FWD_OS_ERROR_NO_STREAM)
|
||||
cnt += 1
|
||||
|
||||
@@ -507,7 +489,7 @@ async def test_forward_runtime_error():
|
||||
cnt = 0
|
||||
|
||||
async def _create_remote():
|
||||
nonlocal cnt
|
||||
nonlocal cnt, remote
|
||||
create_remote(remote, TestType.FWD_RUNTIME_ERROR)
|
||||
cnt += 1
|
||||
|
||||
@@ -525,7 +507,7 @@ async def test_forward_runtime_error2():
|
||||
cnt = 0
|
||||
|
||||
async def _create_remote():
|
||||
nonlocal cnt
|
||||
nonlocal cnt, remote
|
||||
create_remote(remote, TestType.FWD_RUNTIME_ERROR, True)
|
||||
cnt += 1
|
||||
|
||||
@@ -537,14 +519,13 @@ async def test_forward_runtime_error2():
|
||||
del ifc
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_forward_runtime_error3(spy_inc_cnt):
|
||||
async def test_forward_runtime_error3():
|
||||
assert asyncio.get_running_loop()
|
||||
remote = StreamPtr(None)
|
||||
spy = spy_inc_cnt
|
||||
cnt = 0
|
||||
|
||||
async def _create_remote():
|
||||
nonlocal cnt
|
||||
nonlocal cnt, remote
|
||||
create_remote(remote, TestType.FWD_RUNTIME_ERROR_NO_STREAM, True)
|
||||
cnt += 1
|
||||
|
||||
@@ -552,53 +533,41 @@ async def test_forward_runtime_error3(spy_inc_cnt):
|
||||
ifc = AsyncStreamServer(fake_reader_fwd(), FakeWriter(), None, _create_remote, remote)
|
||||
ifc.fwd_add(b'test-forward_msg')
|
||||
await ifc.server_loop()
|
||||
spy.assert_has_calls([call('Inverter_Cnt'), call('ServerMode_Cnt')])
|
||||
assert Infos.get_counter('Inverter_Cnt') == 0
|
||||
assert Infos.get_counter('ServerMode_Cnt') == 0
|
||||
assert cnt == 1
|
||||
del ifc
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_forward_resp(spy_inc_cnt):
|
||||
async def test_forward_resp():
|
||||
assert asyncio.get_running_loop()
|
||||
remote = StreamPtr(None)
|
||||
spy = spy_inc_cnt
|
||||
cnt = 0
|
||||
|
||||
def _close_cb():
|
||||
nonlocal cnt
|
||||
nonlocal cnt, remote, ifc
|
||||
cnt += 1
|
||||
|
||||
cnt = 0
|
||||
ifc = AsyncStreamClient(fake_reader_fwd(), FakeWriter(), remote, _close_cb, use_emu = True)
|
||||
ifc = AsyncStreamClient(fake_reader_fwd(), FakeWriter(), remote, _close_cb)
|
||||
create_remote(remote, TestType.FWD_NO_EXCPT)
|
||||
ifc.fwd_add(b'test-forward_msg')
|
||||
await ifc.client_loop('')
|
||||
spy.assert_has_calls([call('Cloud_Conn_Cnt'), call('EmuMode_Cnt')])
|
||||
assert Infos.get_counter('Cloud_Conn_Cnt') == 0
|
||||
assert Infos.get_counter('EmuMode_Cnt') == 0
|
||||
assert cnt == 1
|
||||
del ifc
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_forward_resp2(spy_inc_cnt):
|
||||
async def test_forward_resp2():
|
||||
assert asyncio.get_running_loop()
|
||||
remote = StreamPtr(None)
|
||||
spy = spy_inc_cnt
|
||||
cnt = 0
|
||||
|
||||
def _close_cb():
|
||||
nonlocal cnt
|
||||
nonlocal cnt, remote, ifc
|
||||
cnt += 1
|
||||
|
||||
cnt = 0
|
||||
ifc = AsyncStreamClient(fake_reader_fwd(), FakeWriter(), None, _close_cb, use_emu = False)
|
||||
ifc = AsyncStreamClient(fake_reader_fwd(), FakeWriter(), None, _close_cb)
|
||||
create_remote(remote, TestType.FWD_NO_EXCPT)
|
||||
ifc.fwd_add(b'test-forward_msg')
|
||||
await ifc.client_loop('')
|
||||
spy.assert_has_calls([call('Cloud_Conn_Cnt'), call('ProxyMode_Cnt'), call('SW_Exception')])
|
||||
assert Infos.get_counter('Cloud_Conn_Cnt') == 0
|
||||
assert Infos.get_counter('ProxyMode_Cnt') == 0
|
||||
assert cnt == 1
|
||||
del ifc
|
||||
|
||||
@@ -17,13 +17,13 @@ def test_statistic_counter():
|
||||
assert val == None or val == 0
|
||||
|
||||
i.static_init() # initialize counter
|
||||
assert json.dumps(i.stat) == json.dumps({"proxy": {"Inverter_Cnt": 0, "Cloud_Conn_Cnt": 0, "Unknown_SNR": 0, "Unknown_Msg": 0, "Invalid_Data_Type": 0, "Internal_Error": 0,"Unknown_Ctrl": 0, "OTA_Start_Msg": 0, "SW_Exception": 0, "Invalid_Msg_Format": 0, "AT_Command": 0, "AT_Command_Blocked": 0, "DCU_Command": 0, "Modbus_Command": 0}})
|
||||
assert json.dumps(i.stat) == json.dumps({"proxy": {"Inverter_Cnt": 0, "Cloud_Conn_Cnt": 0, "Unknown_SNR": 0, "Unknown_Msg": 0, "Invalid_Data_Type": 0, "Internal_Error": 0,"Unknown_Ctrl": 0, "OTA_Start_Msg": 0, "SW_Exception": 0, "Invalid_Msg_Format": 0, "AT_Command": 0, "AT_Command_Blocked": 0, "Modbus_Command": 0}})
|
||||
|
||||
val = i.dev_value(Register.INVERTER_CNT) # valid and initiliazed addr
|
||||
assert val == 0
|
||||
|
||||
i.inc_counter('Inverter_Cnt')
|
||||
assert json.dumps(i.stat) == json.dumps({"proxy": {"Inverter_Cnt": 1, "Cloud_Conn_Cnt": 0, "Unknown_SNR": 0, "Unknown_Msg": 0, "Invalid_Data_Type": 0, "Internal_Error": 0,"Unknown_Ctrl": 0, "OTA_Start_Msg": 0, "SW_Exception": 0, "Invalid_Msg_Format": 0, "AT_Command": 0, "AT_Command_Blocked": 0, "DCU_Command": 0, "Modbus_Command": 0}})
|
||||
assert json.dumps(i.stat) == json.dumps({"proxy": {"Inverter_Cnt": 1, "Cloud_Conn_Cnt": 0, "Unknown_SNR": 0, "Unknown_Msg": 0, "Invalid_Data_Type": 0, "Internal_Error": 0,"Unknown_Ctrl": 0, "OTA_Start_Msg": 0, "SW_Exception": 0, "Invalid_Msg_Format": 0, "AT_Command": 0, "AT_Command_Blocked": 0, "Modbus_Command": 0}})
|
||||
val = i.dev_value(Register.INVERTER_CNT)
|
||||
assert val == 1
|
||||
|
||||
|
||||
@@ -221,7 +221,7 @@ def inv_data_seq2(): # Data indication from the controller
|
||||
return msg
|
||||
|
||||
@pytest.fixture
|
||||
def inv_data_seq3(): # Inverter indication from MS-3000
|
||||
def inv_data_seq3(): # Inverter indication from MS-2000
|
||||
|
||||
msg = b'\x00\x00\x01\x2c\x00\x00\x00\x64\x53\x00\x00' # | ..^.....,...dS..
|
||||
msg += b'\x00\x00\x00\xc8\x53\x44\x00\x00\x00\x01\x2c\x53\x00\x00\x00\x00' # | ....SD....,S....
|
||||
|
||||
@@ -82,25 +82,13 @@ def batterie_data(): # 0x4210 ftype: 0x01
|
||||
msg += b'\x00\x00\x00\x0f\x00\x00\x02\x05\x02\x01'
|
||||
return msg
|
||||
|
||||
@pytest.fixture
|
||||
def batterie_data1(): # 0x4210 ftype: 0x01
|
||||
msg = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x26\x30\xc7\xde'
|
||||
msg += b'\x2d\x32\x28\x00\x00\x00\x84\x17\x79\x35\x01\x00\x4c\x12\x00\x00'
|
||||
msg += b'\x34\x31\x30\x31\x32\x34\x30\x37\x30\x31\x34\x39\x30\x33\x31\x34'
|
||||
msg += b'\x0d\x3a\x00\x70\x0d\x2c\x00\x00\x00\x00\x08\x20\x00\x00\x00\x00'
|
||||
msg += b'\x01\x00\x00\x00\x03\xe8\x0c\x89\x0c\x89\x0c\x89\x0c\x8a\x0c\x89'
|
||||
msg += b'\x0c\x89\x0c\x8a\x0c\x89\x0c\x89\x0c\x8a\x0c\x8a\x0c\x89\x0c\x89'
|
||||
msg += b'\x0c\x89\x0c\x89\x0c\x88\x00\x0f\x00\x0f\x00\x0f\x0c\x0e\x01\x00'
|
||||
msg += b'\x00\x00\x00\x0f\x00\x00\x02\x05\x02\x01'
|
||||
return msg
|
||||
|
||||
@pytest.fixture
|
||||
def batterie_data2(): # 0x4210 ftype: 0x01
|
||||
msg = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x26\x30\xc7\xde'
|
||||
msg += b'\x2d\x32\x28\x00\x00\x00\x84\x17\x79\x35\x01\x00\x4c\x12\x00\x00'
|
||||
msg += b'\x34\x31\x30\x31\x32\x34\x30\x37\x30\x31\x34\x39\x30\x33\x31\x34'
|
||||
msg += b'\x0d\x3a\x00\x70\x0d\x2c\x00\x00\x00\x00\x08\x20\x00\x00\x00\x00'
|
||||
msg += b'\x14\x0e\x02\xfe\x03\xe8\x0c\x89\x0c\x89\x0c\x89\x0c\x8a\x0c\x89'
|
||||
msg += b'\x14\x0e\xff\xfe\x03\xe8\x0c\x89\x0c\x89\x0c\x89\x0c\x8a\x0c\x89'
|
||||
msg += b'\x0c\x89\x0c\x8a\x0c\x89\x0c\x89\x0c\x8a\x0c\x8a\x0c\x89\x0c\x89'
|
||||
msg += b'\x0c\x89\x0c\x89\x0c\x88\x00\x0f\x00\x0f\x00\x0f\x00\x0e'
|
||||
return msg
|
||||
@@ -109,7 +97,7 @@ def test_default_db():
|
||||
i = InfosG3P(client_mode=False)
|
||||
|
||||
assert json.dumps(i.db) == json.dumps({
|
||||
"inverter": {"Manufacturer": "TSUN", "Equipment_Model": "TSOL-MSxx00", "No_Inputs": 2},
|
||||
"inverter": {"Manufacturer": "TSUN", "Equipment_Model": "TSOL-MSxx00", "No_Inputs": 4},
|
||||
"collector": {"Chip_Type": "IGEN TECH"},
|
||||
})
|
||||
|
||||
@@ -167,32 +155,15 @@ def test_parse_4210_3026(batterie_data: bytes):
|
||||
assert json.dumps(i.db) == json.dumps({
|
||||
"controller": {"Sensor_List": "3026", "Power_On_Time": 4684},
|
||||
"inverter": {"Serial_Number": "4101240701490314"},
|
||||
"batterie": {"pv1": {"Voltage": 33.86, "Current": 1.12, "MPPT-Status": 0},
|
||||
"pv2": {"Voltage": 33.72, "Current": 0.0, "MPPT-Status": 0},
|
||||
"batt": {"Total_Charging": 20.8, "Voltage": 51.34, "Current": -0.02, "SOC": 10.0, "Power": -1.0268000000000002, 'Batt_State': 0},
|
||||
"cell": {"Volt1": 3.21, "Volt2": 3.21, "Volt3": 3.21, "Volt4": 3.21, "Volt5": 3.21, "Volt6": 3.21, "Volt7": 3.21, "Volt8": 3.21, "Volt9": 3.21, "Volt10": 3.21, "Volt11": 3.21, "Volt12": 3.21, "Volt13": 3.21, "Volt14": 3.21, "Volt15": 3.21, "Volt16": 3.21, "Temp_1": 15, "Temp_2": 15, "Temp_3": 15},
|
||||
"out": {"Voltage": 0.14, "Current": 0.0, "Out_Status": 0, "Power": 0.0, "Suppl_State": 0},
|
||||
"Controller_Temp": 15, "Batterie_Alarm": 0, "Hardware_Version": 517, "Software_Version": 513,
|
||||
"PV_Power": 37.9232},
|
||||
})
|
||||
|
||||
def test_parse_4210_3026_prod(batterie_data1: bytes):
|
||||
i = InfosG3P(client_mode=False)
|
||||
i.db.clear()
|
||||
|
||||
for key, update in i.parse (batterie_data1, 0x42, 1, 0x3026):
|
||||
pass # side effect is calling generator i.parse()
|
||||
|
||||
assert json.dumps(i.db) == json.dumps({
|
||||
"controller": {"Sensor_List": "3026", "Power_On_Time": 4684},
|
||||
"inverter": {"Serial_Number": "4101240701490314"},
|
||||
"batterie": {"pv1": {"Voltage": 33.86, "Current": 1.12, "MPPT-Status": 0},
|
||||
"pv2": {"Voltage": 33.72, "Current": 0.0, "MPPT-Status": 0},
|
||||
"batt": {"Total_Charging": 20.8, "Voltage": 2.56, "Current": 0.0, "SOC": 10.0, "Power": 0.0, 'Batt_State': 1},
|
||||
"cell": {"Volt1": 3.21, "Volt2": 3.21, "Volt3": 3.21, "Volt4": 3.21, "Volt5": 3.21, "Volt6": 3.21, "Volt7": 3.21, "Volt8": 3.21, "Volt9": 3.21, "Volt10": 3.21, "Volt11": 3.21, "Volt12": 3.21, "Volt13": 3.21, "Volt14": 3.21, "Volt15": 3.21, "Volt16": 3.21, "Temp_1": 15, "Temp_2": 15, "Temp_3": 15},
|
||||
"out": {"Voltage": 30.86, "Current": 2.56, "Out_Status": 0, "Power": 79.0016, "Suppl_State": 1},
|
||||
"Controller_Temp": 15, "Batterie_Alarm": 0, "Hardware_Version": 517, "Software_Version": 513,
|
||||
"PV_Power": 37.9232},
|
||||
"batterie": {"pv1": {"Voltage": 33.86, "Current": 1.12},
|
||||
"pv2": {"Voltage": 33.72, "Current": 0.0},
|
||||
"Reg_38": 0, "Total_Generation": 20.8, "Status_1": 0, "Status_2": 0,
|
||||
"Voltage": 51.34, "Current": -0.02, "SOC": 10.0,
|
||||
"Cell": {"Volt1": 3.21, "Volt2": 3.21, "Volt3": 3.21, "Volt4": 3.21, "Volt5": 3.21, "Volt6": 3.21, "Volt7": 3.21, "Volt8": 3.21, "Volt9": 3.21, "Volt10": 3.21, "Volt11": 3.21, "Volt12": 3.21, "Volt13": 3.21, "Volt14": 3.21, "Volt15": 3.21, "Volt16": 3.21},
|
||||
"Temp_1": 15, "Temp_2": 15, "Temp_3": 15,
|
||||
"out": {"Voltage": 0.14, "Current": 0.0, "Out_Status": 0, "Power": 0.0},
|
||||
"Controller_Temp": 15, "Reg_74": 0, "Reg_76": 517, "Reg_78": 513,
|
||||
"PV_Power": 37.9232, "Power": -1.0268000000000002},
|
||||
})
|
||||
|
||||
def test_parse_4210_3026_incomplete(batterie_data2: bytes):
|
||||
@@ -205,14 +176,16 @@ def test_parse_4210_3026_incomplete(batterie_data2: bytes):
|
||||
assert json.dumps(i.db) == json.dumps({
|
||||
"controller": {"Sensor_List": "3026", "Power_On_Time": 4684},
|
||||
"inverter": {"Serial_Number": "4101240701490314"},
|
||||
"batterie": {"pv1": {"Voltage": 33.86, "Current": 1.12, "MPPT-Status": 0},
|
||||
"pv2": {"Voltage": 33.72, "Current": 0.0, "MPPT-Status": 0},
|
||||
"batt": {"Total_Charging": 20.8, "Voltage": 51.34, "Current": 7.66, "SOC": 10.0, "Power": 393.2644, 'Batt_State': 2},
|
||||
"cell": {"Volt1": 3.21, "Volt2": 3.21, "Volt3": 3.21, "Volt4": 3.21, "Volt5": 3.21, "Volt6": 3.21, "Volt7": 3.21, "Volt8": 3.21, "Volt9": 3.21, "Volt10": 3.21, "Volt11": 3.21, "Volt12": 3.21, "Volt13": 3.21, "Volt14": 3.21, "Volt15": 3.21, "Volt16": 3.21, "Temp_1": 15, "Temp_2": 15, "Temp_3": 15},
|
||||
"out": {"Voltage": 0.14, "Current": None, "Out_Status": None, "Power": None, "Suppl_State": None},
|
||||
"Controller_Temp": None, "Batterie_Alarm": None, "Hardware_Version": None, "Software_Version": None,
|
||||
"PV_Power": 37.9232},
|
||||
})
|
||||
"batterie": {"pv1": {"Voltage": 33.86, "Current": 1.12},
|
||||
"pv2": {"Voltage": 33.72, "Current": 0.0},
|
||||
"Reg_38": 0, "Total_Generation": 20.8, "Status_1": 0, "Status_2": 0,
|
||||
"Voltage": 51.34, "Current": -0.02, "SOC": 10.0,
|
||||
"Cell": {"Volt1": 3.21, "Volt2": 3.21, "Volt3": 3.21, "Volt4": 3.21, "Volt5": 3.21, "Volt6": 3.21, "Volt7": 3.21, "Volt8": 3.21, "Volt9": 3.21, "Volt10": 3.21, "Volt11": 3.21, "Volt12": 3.21, "Volt13": 3.21, "Volt14": 3.21, "Volt15": 3.21, "Volt16": 3.21},
|
||||
"Temp_1": 15, "Temp_2": 15, "Temp_3": 15,
|
||||
"out": {"Voltage": 0.14, "Current": None, "Out_Status": None, "Power": None},
|
||||
"Controller_Temp": None, "Reg_74": None, "Reg_76": None, "Reg_78": None,
|
||||
"PV_Power": 37.9232, "Power": -1.0268000000000002},
|
||||
})
|
||||
|
||||
def test_build_4210(inverter_data: bytes):
|
||||
i = InfosG3P(client_mode=False)
|
||||
@@ -271,7 +244,7 @@ def test_build_ha_conf1():
|
||||
elif id == 'inv_count_456':
|
||||
assert False
|
||||
|
||||
assert tests==5
|
||||
assert tests==7
|
||||
|
||||
def test_build_ha_conf2():
|
||||
i = InfosG3P(client_mode=False)
|
||||
@@ -346,7 +319,7 @@ def test_build_ha_conf3():
|
||||
elif id == 'inv_count_456':
|
||||
assert False
|
||||
|
||||
assert tests==5
|
||||
assert tests==7
|
||||
|
||||
def test_build_ha_conf4():
|
||||
i = InfosG3P(client_mode=True)
|
||||
@@ -386,7 +359,7 @@ def test_build_ha_conf5():
|
||||
|
||||
if id == 'out_power_123':
|
||||
assert comp == 'sensor'
|
||||
assert d_json == json.dumps({"name": "Supply Power", "stat_t": "tsun/garagendach/batterie", "dev_cla": "power", "stat_cla": "measurement", "uniq_id": "out_power_123", "val_tpl": "{{ (value_json['out']['Power'] | int)}}", "unit_of_meas": "W", "dev": {"name": "Batterie", "sa": "Batterie", "via_device": "controller_123", "mdl": "TSOL-MSxx00", "mf": "TSUN", "ids": ["batterie_123"]}, "o": {"name": "proxy", "sw": "unknown"}})
|
||||
assert d_json == json.dumps({"name": "Output Power", "stat_t": "tsun/garagendach/batterie", "dev_cla": "power", "stat_cla": "measurement", "uniq_id": "out_power_123", "val_tpl": "{{ (value_json['out']['Power'] | int)}}", "unit_of_meas": "W", "dev": {"name": "Batterie", "sa": "Batterie", "via_device": "controller_123", "mdl": "TSOL-MSxx00", "mf": "TSUN", "ids": ["batterie_123"]}, "o": {"name": "proxy", "sw": "unknown"}})
|
||||
tests +=1
|
||||
elif id == 'daily_gen_123':
|
||||
assert False
|
||||
|
||||
@@ -85,6 +85,7 @@ def patch_open_connection():
|
||||
return FakeReader(), FakeWriter()
|
||||
|
||||
def new_open(host: str, port: int):
|
||||
global test
|
||||
if test == MockType.RD_TEST_TIMEOUT:
|
||||
raise ConnectionRefusedError
|
||||
elif test == MockType.RD_TEST_EXCEPT:
|
||||
@@ -113,9 +114,7 @@ def patch_unhealthy_remote():
|
||||
with patch.object(AsyncStreamClient, 'healthy', new_healthy) as conn:
|
||||
yield conn
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_inverter_iter(my_loop):
|
||||
_ = my_loop
|
||||
def test_inverter_iter():
|
||||
InverterBase._registry.clear()
|
||||
cnt = 0
|
||||
reader = FakeReader()
|
||||
@@ -218,8 +217,7 @@ def test_unhealthy_remote(patch_unhealthy_remote):
|
||||
assert cnt == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_remote_conn(my_loop, config_conn, patch_open_connection):
|
||||
_ = my_loop
|
||||
async def test_remote_conn(config_conn, patch_open_connection):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
assert asyncio.get_running_loop()
|
||||
@@ -245,9 +243,8 @@ async def test_remote_conn(my_loop, config_conn, patch_open_connection):
|
||||
assert cnt == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_remote_conn_to_private(my_loop, config_conn, patch_open_connection):
|
||||
async def test_remote_conn_to_private(config_conn, patch_open_connection):
|
||||
'''check DNS resolving of the TSUN FQDN to a local address'''
|
||||
_ = my_loop
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
assert asyncio.get_running_loop()
|
||||
@@ -284,9 +281,8 @@ async def test_remote_conn_to_private(my_loop, config_conn, patch_open_connectio
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_remote_conn_to_loopback(my_loop, config_conn, patch_open_connection):
|
||||
async def test_remote_conn_to_loopback(config_conn, patch_open_connection):
|
||||
'''check DNS resolving of the TSUN FQDN to the loopback address'''
|
||||
_ = my_loop
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
assert asyncio.get_running_loop()
|
||||
@@ -322,9 +318,8 @@ async def test_remote_conn_to_loopback(my_loop, config_conn, patch_open_connecti
|
||||
assert cnt == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_remote_conn_to_none(my_loop, config_conn, patch_open_connection):
|
||||
async def test_remote_conn_to_None(config_conn, patch_open_connection):
|
||||
'''check if get_extra_info() return None in case of an error'''
|
||||
_ = my_loop
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
assert asyncio.get_running_loop()
|
||||
@@ -360,8 +355,7 @@ async def test_remote_conn_to_none(my_loop, config_conn, patch_open_connection):
|
||||
assert cnt == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_unhealthy_remote(my_loop, config_conn, patch_open_connection, patch_unhealthy_remote):
|
||||
_ = my_loop
|
||||
async def test_unhealthy_remote(config_conn, patch_open_connection, patch_unhealthy_remote):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
_ = patch_unhealthy_remote
|
||||
@@ -398,10 +392,10 @@ async def test_unhealthy_remote(my_loop, config_conn, patch_open_connection, pat
|
||||
assert cnt == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_remote_disc(my_loop, config_conn, patch_open_connection):
|
||||
_ = my_loop
|
||||
async def test_remote_disc(config_conn, patch_open_connection):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
assert asyncio.get_running_loop()
|
||||
reader = FakeReader()
|
||||
writer = FakeWriter()
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@ def patch_open_connection():
|
||||
return FakeReader(), FakeWriter()
|
||||
|
||||
def new_open(host: str, port: int):
|
||||
global test
|
||||
if test == MockType.RD_TEST_TIMEOUT:
|
||||
raise ConnectionRefusedError
|
||||
elif test == MockType.RD_TEST_EXCEPT:
|
||||
@@ -99,8 +100,7 @@ def patch_healthy():
|
||||
with patch.object(AsyncStream, 'healthy') as conn:
|
||||
yield conn
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_method_calls(my_loop, patch_healthy):
|
||||
def test_method_calls(patch_healthy):
|
||||
spy = patch_healthy
|
||||
reader = FakeReader()
|
||||
writer = FakeWriter()
|
||||
@@ -120,7 +120,7 @@ async def test_method_calls(my_loop, patch_healthy):
|
||||
assert cnt == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_remote_conn(my_loop, config_conn, patch_open_connection):
|
||||
async def test_remote_conn(config_conn, patch_open_connection):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
assert asyncio.get_running_loop()
|
||||
@@ -138,7 +138,7 @@ async def test_remote_conn(my_loop, config_conn, patch_open_connection):
|
||||
assert cnt == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_remote_except(my_loop, config_conn, patch_open_connection):
|
||||
async def test_remote_except(config_conn, patch_open_connection):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
assert asyncio.get_running_loop()
|
||||
@@ -156,7 +156,6 @@ async def test_remote_except(my_loop, config_conn, patch_open_connection):
|
||||
await asyncio.sleep(0)
|
||||
assert inverter.remote.stream==None
|
||||
del inverter
|
||||
test = MockType.RD_TEST_0_BYTES
|
||||
|
||||
cnt = 0
|
||||
for inv in InverterBase:
|
||||
@@ -165,7 +164,7 @@ async def test_remote_except(my_loop, config_conn, patch_open_connection):
|
||||
assert cnt == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mqtt_publish(my_loop, config_conn, patch_open_connection):
|
||||
async def test_mqtt_publish(config_conn, patch_open_connection):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
assert asyncio.get_running_loop()
|
||||
@@ -192,7 +191,7 @@ async def test_mqtt_publish(my_loop, config_conn, patch_open_connection):
|
||||
assert Infos.new_stat_data['proxy'] == False
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mqtt_err(my_loop, config_conn, patch_open_connection, patch_mqtt_err):
|
||||
async def test_mqtt_err(config_conn, patch_open_connection, patch_mqtt_err):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
_ = patch_mqtt_err
|
||||
@@ -209,7 +208,7 @@ async def test_mqtt_err(my_loop, config_conn, patch_open_connection, patch_mqtt_
|
||||
assert stream.new_data['inverter'] == True
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mqtt_except(my_loop, config_conn, patch_open_connection, patch_mqtt_except):
|
||||
async def test_mqtt_except(config_conn, patch_open_connection, patch_mqtt_except):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
_ = patch_mqtt_except
|
||||
|
||||
@@ -37,7 +37,6 @@ def config_conn():
|
||||
},
|
||||
'solarman':{'enabled': True, 'host': 'test_cloud.local', 'port': 1234}, 'inverters':{'allow_all':True}
|
||||
}
|
||||
Config.log_path='app/tests/log/'
|
||||
|
||||
@pytest.fixture(scope="module", autouse=True)
|
||||
def module_init():
|
||||
@@ -85,6 +84,7 @@ def patch_open_connection():
|
||||
return FakeReader(), FakeWriter()
|
||||
|
||||
def new_open(host: str, port: int):
|
||||
global test
|
||||
if test == MockType.RD_TEST_TIMEOUT:
|
||||
raise ConnectionRefusedError
|
||||
elif test == MockType.RD_TEST_EXCEPT:
|
||||
@@ -94,8 +94,7 @@ def patch_open_connection():
|
||||
with patch.object(asyncio, 'open_connection', new_open) as conn:
|
||||
yield conn
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_method_calls(my_loop, config_conn):
|
||||
def test_method_calls(config_conn):
|
||||
_ = config_conn
|
||||
reader = FakeReader()
|
||||
writer = FakeWriter()
|
||||
@@ -106,7 +105,7 @@ async def test_method_calls(my_loop, config_conn):
|
||||
assert inverter.local.ifc
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_remote_conn(my_loop, config_conn, patch_open_connection):
|
||||
async def test_remote_conn(config_conn, patch_open_connection):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
assert asyncio.get_running_loop()
|
||||
@@ -117,7 +116,7 @@ async def test_remote_conn(my_loop, config_conn, patch_open_connection):
|
||||
assert inverter.remote.stream
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_remote_except(my_loop, config_conn, patch_open_connection):
|
||||
async def test_remote_except(config_conn, patch_open_connection):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
assert asyncio.get_running_loop()
|
||||
@@ -135,11 +134,8 @@ async def test_remote_except(my_loop, config_conn, patch_open_connection):
|
||||
await asyncio.sleep(0)
|
||||
assert inverter.remote.stream==None
|
||||
|
||||
test = MockType.RD_TEST_0_BYTES
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mqtt_publish(my_loop, config_conn, patch_open_connection):
|
||||
async def test_mqtt_publish(config_conn, patch_open_connection):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
assert asyncio.get_running_loop()
|
||||
@@ -166,7 +162,7 @@ async def test_mqtt_publish(my_loop, config_conn, patch_open_connection):
|
||||
assert Infos.new_stat_data['proxy'] == False
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mqtt_err(my_loop, config_conn, patch_open_connection, patch_mqtt_err):
|
||||
async def test_mqtt_err(config_conn, patch_open_connection, patch_mqtt_err):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
_ = patch_mqtt_err
|
||||
@@ -183,7 +179,7 @@ async def test_mqtt_err(my_loop, config_conn, patch_open_connection, patch_mqtt_
|
||||
assert stream.new_data['inverter'] == True
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mqtt_except(my_loop, config_conn, patch_open_connection, patch_mqtt_except):
|
||||
async def test_mqtt_except(config_conn, patch_open_connection, patch_mqtt_except):
|
||||
_ = config_conn
|
||||
_ = patch_open_connection
|
||||
_ = patch_mqtt_except
|
||||
|
||||
@@ -19,8 +19,7 @@ class ModbusTestHelper(Modbus):
|
||||
def resp_handler(self):
|
||||
self.recv_responses += 1
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_modbus_crc():
|
||||
def test_modbus_crc():
|
||||
'''Check CRC-16 calculation'''
|
||||
mb = Modbus(None)
|
||||
assert 0x0b02 == mb._Modbus__calc_crc(b'\x01\x06\x20\x08\x00\x04')
|
||||
@@ -38,8 +37,7 @@ async def test_modbus_crc():
|
||||
msg += b'\x00\x00\x00\x00\x00\x00\x00\xe6\xef'
|
||||
assert 0 == mb._Modbus__calc_crc(msg)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_build_modbus_pdu():
|
||||
def test_build_modbus_pdu():
|
||||
'''Check building and sending a MODBUS RTU'''
|
||||
mb = ModbusTestHelper()
|
||||
mb.build_msg(1,6,0x2000,0x12)
|
||||
@@ -51,8 +49,7 @@ async def test_build_modbus_pdu():
|
||||
assert mb.last_len == 18
|
||||
assert mb.err == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_recv_req():
|
||||
def test_recv_req():
|
||||
'''Receive a valid request, which must transmitted'''
|
||||
mb = ModbusTestHelper()
|
||||
assert mb.recv_req(b'\x01\x06\x20\x00\x00\x12\x02\x07')
|
||||
@@ -61,8 +58,7 @@ async def test_recv_req():
|
||||
assert mb.last_len == 0x12
|
||||
assert mb.err == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_recv_req_crc_err():
|
||||
def test_recv_req_crc_err():
|
||||
'''Receive a request with invalid CRC, which must be dropped'''
|
||||
mb = ModbusTestHelper()
|
||||
assert not mb.recv_req(b'\x01\x06\x20\x00\x00\x12\x02\x08')
|
||||
@@ -72,8 +68,7 @@ async def test_recv_req_crc_err():
|
||||
assert mb.last_len == 0
|
||||
assert mb.err == 1
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_recv_resp_crc_err():
|
||||
def test_recv_resp_crc_err():
|
||||
'''Receive a response with invalid CRC, which must be dropped'''
|
||||
mb = ModbusTestHelper()
|
||||
# simulate a transmitted request
|
||||
@@ -94,8 +89,7 @@ async def test_recv_resp_crc_err():
|
||||
mb._Modbus__stop_timer()
|
||||
assert not mb.req_pend
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_recv_resp_invalid_addr():
|
||||
def test_recv_resp_invalid_addr():
|
||||
'''Receive a response with wrong server addr, which must be dropped'''
|
||||
mb = ModbusTestHelper()
|
||||
mb.req_pend = True
|
||||
@@ -119,8 +113,7 @@ async def test_recv_resp_invalid_addr():
|
||||
mb._Modbus__stop_timer()
|
||||
assert not mb.req_pend
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_recv_recv_fcode():
|
||||
def test_recv_recv_fcode():
|
||||
'''Receive a response with wrong function code, which must be dropped'''
|
||||
mb = ModbusTestHelper()
|
||||
mb.build_msg(1,4,0x300e,2)
|
||||
@@ -142,8 +135,7 @@ async def test_recv_recv_fcode():
|
||||
mb._Modbus__stop_timer()
|
||||
assert not mb.req_pend
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_recv_resp_len():
|
||||
def test_recv_resp_len():
|
||||
'''Receive a response with wrong data length, which must be dropped'''
|
||||
mb = ModbusTestHelper()
|
||||
mb.build_msg(1,3,0x300e,3)
|
||||
@@ -166,8 +158,7 @@ async def test_recv_resp_len():
|
||||
mb._Modbus__stop_timer()
|
||||
assert not mb.req_pend
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_recv_unexpect_resp():
|
||||
def test_recv_unexpect_resp():
|
||||
'''Receive a response when we havb't sent a request'''
|
||||
mb = ModbusTestHelper()
|
||||
assert not mb.req_pend
|
||||
@@ -183,8 +174,7 @@ async def test_recv_unexpect_resp():
|
||||
assert mb.req_pend == False
|
||||
assert mb.que.qsize() == 0
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_parse_resp():
|
||||
def test_parse_resp():
|
||||
'''Receive matching response and parse the values'''
|
||||
mb = ModbusTestHelper()
|
||||
mb.build_msg(1,3,0x3007,6)
|
||||
@@ -210,8 +200,7 @@ async def test_parse_resp():
|
||||
assert mb.que.qsize() == 0
|
||||
assert not mb.req_pend
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_queue():
|
||||
def test_queue():
|
||||
mb = ModbusTestHelper()
|
||||
mb.build_msg(1,3,0x3022,4)
|
||||
assert mb.que.qsize() == 0
|
||||
@@ -229,8 +218,7 @@ async def test_queue():
|
||||
mb._Modbus__stop_timer()
|
||||
assert not mb.req_pend
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_queue2():
|
||||
def test_queue2():
|
||||
'''Check queue handling for build_msg() calls'''
|
||||
mb = ModbusTestHelper()
|
||||
mb.build_msg(1,3,0x3007,6)
|
||||
@@ -279,8 +267,7 @@ async def test_queue2():
|
||||
assert mb.que.qsize() == 0
|
||||
assert not mb.req_pend
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_queue3():
|
||||
def test_queue3():
|
||||
'''Check queue handling for recv_req() calls'''
|
||||
mb = ModbusTestHelper()
|
||||
assert mb.recv_req(b'\x01\x03\x30\x07\x00\x06{\t', mb.resp_handler)
|
||||
@@ -337,7 +324,7 @@ async def test_queue3():
|
||||
assert not mb.req_pend
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_timeout(my_loop):
|
||||
async def test_timeout():
|
||||
'''Test MODBUS response timeout and RTU retransmitting'''
|
||||
assert asyncio.get_running_loop()
|
||||
mb = ModbusTestHelper()
|
||||
@@ -384,8 +371,7 @@ async def test_timeout(my_loop):
|
||||
assert mb.retry_cnt == 0
|
||||
assert mb.send_calls == 4
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_recv_unknown_data():
|
||||
def test_recv_unknown_data():
|
||||
'''Receive a response with an unknwon register'''
|
||||
mb = ModbusTestHelper()
|
||||
assert 0x9000 not in mb.mb_reg_mapping
|
||||
@@ -404,8 +390,7 @@ async def test_recv_unknown_data():
|
||||
|
||||
del mb.mb_reg_mapping[0x9000]
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_close():
|
||||
def test_close():
|
||||
'''Check queue handling for build_msg() calls'''
|
||||
mb = ModbusTestHelper()
|
||||
mb.build_msg(1,3,0x3007,6)
|
||||
|
||||
@@ -190,8 +190,7 @@ def patch_mqtt_except():
|
||||
yield conn
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_modbus_conn(config_conn, patch_open):
|
||||
_ = config_conn
|
||||
async def test_modbus_conn(patch_open):
|
||||
_ = patch_open
|
||||
assert Infos.stat['proxy']['Inverter_Cnt'] == 0
|
||||
|
||||
@@ -211,7 +210,6 @@ async def test_modbus_conn(config_conn, patch_open):
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_modbus_no_cnf():
|
||||
_ = config_conn
|
||||
assert Infos.stat['proxy']['Inverter_Cnt'] == 0
|
||||
loop = asyncio.get_event_loop()
|
||||
ModbusTcp(loop)
|
||||
|
||||
268
app/tests/test_mqtt.py
Executable file → Normal file
@@ -3,10 +3,8 @@ import pytest
|
||||
import asyncio
|
||||
import aiomqtt
|
||||
import logging
|
||||
from aiomqtt import MqttError, MessagesIterator
|
||||
from aiomqtt import Message as AiomqttMessage
|
||||
from mock import patch, Mock
|
||||
|
||||
from mock import patch, Mock
|
||||
from async_stream import AsyncIfcImpl
|
||||
from singleton import Singleton
|
||||
from mqtt import Mqtt
|
||||
@@ -19,7 +17,7 @@ NO_MOSQUITTO_TEST = False
|
||||
|
||||
pytest_plugins = ('pytest_asyncio',)
|
||||
|
||||
@pytest.fixture(scope="function", autouse=True)
|
||||
@pytest.fixture(scope="module", autouse=True)
|
||||
def module_init():
|
||||
Singleton._instances.clear()
|
||||
yield
|
||||
@@ -35,26 +33,6 @@ def test_hostname():
|
||||
# else:
|
||||
return 'test.mosquitto.org'
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def aiomqtt_mock(monkeypatch):
|
||||
recv_que = asyncio.Queue()
|
||||
|
||||
async def my_aenter(self):
|
||||
return self
|
||||
async def my_subscribe(self, *arg):
|
||||
return
|
||||
async def my_anext(self):
|
||||
return await recv_que.get()
|
||||
async def my_receive(self, topic: str, payload: bytes):
|
||||
msg = AiomqttMessage(topic, payload,qos=0, retain=False, mid=0, properties=None)
|
||||
await recv_que.put(msg)
|
||||
await asyncio.sleep(0) # dispath the msg
|
||||
|
||||
monkeypatch.setattr(aiomqtt.Client, "__aenter__", my_aenter)
|
||||
monkeypatch.setattr(aiomqtt.Client, "subscribe", my_subscribe)
|
||||
monkeypatch.setattr(MessagesIterator, "__anext__", my_anext)
|
||||
monkeypatch.setattr(Mqtt, "receive", my_receive, False)
|
||||
|
||||
@pytest.fixture
|
||||
def config_mqtt_conn(test_hostname, test_port):
|
||||
Config.act_config = {'mqtt':{'host': test_hostname, 'port': test_port, 'user': '', 'passwd': ''},
|
||||
@@ -66,18 +44,10 @@ def config_no_conn(test_port):
|
||||
Config.act_config = {'mqtt':{'host': "", 'port': test_port, 'user': '', 'passwd': ''},
|
||||
'ha':{'auto_conf_prefix': 'homeassistant','discovery_prefix': 'homeassistant', 'entity_prefix': 'tsun'}
|
||||
}
|
||||
Config.def_config = {}
|
||||
|
||||
@pytest.fixture
|
||||
def config_def_conn(test_port):
|
||||
Config.act_config = {'mqtt':{'host': "unknown_url", 'port': test_port, 'user': '', 'passwd': ''},
|
||||
'ha':{'auto_conf_prefix': 'homeassistant','discovery_prefix': 'homeassistant', 'entity_prefix': 'tsun'}
|
||||
}
|
||||
Config.def_config = Config.act_config
|
||||
|
||||
@pytest.fixture
|
||||
def spy_at_cmd():
|
||||
conn = SolarmanV5(None, ('test.local', 1234), server_side=True, client_mode= False, ifc=AsyncIfcImpl())
|
||||
conn = SolarmanV5(('test.local', 1234), server_side=True, client_mode= False, ifc=AsyncIfcImpl())
|
||||
conn.node_id = 'inv_2/'
|
||||
with patch.object(conn, 'send_at_cmd', wraps=conn.send_at_cmd) as wrapped_conn:
|
||||
yield wrapped_conn
|
||||
@@ -85,7 +55,7 @@ def spy_at_cmd():
|
||||
|
||||
@pytest.fixture
|
||||
def spy_modbus_cmd():
|
||||
conn = SolarmanV5(None, ('test.local', 1234), server_side=True, client_mode= False, ifc=AsyncIfcImpl())
|
||||
conn = SolarmanV5(('test.local', 1234), server_side=True, client_mode= False, ifc=AsyncIfcImpl())
|
||||
conn.node_id = 'inv_1/'
|
||||
with patch.object(conn, 'send_modbus_cmd', wraps=conn.send_modbus_cmd) as wrapped_conn:
|
||||
yield wrapped_conn
|
||||
@@ -93,20 +63,12 @@ def spy_modbus_cmd():
|
||||
|
||||
@pytest.fixture
|
||||
def spy_modbus_cmd_client():
|
||||
conn = SolarmanV5(None, ('test.local', 1234), server_side=False, client_mode= False, ifc=AsyncIfcImpl())
|
||||
conn = SolarmanV5(('test.local', 1234), server_side=False, client_mode= False, ifc=AsyncIfcImpl())
|
||||
conn.node_id = 'inv_1/'
|
||||
with patch.object(conn, 'send_modbus_cmd', wraps=conn.send_modbus_cmd) as wrapped_conn:
|
||||
yield wrapped_conn
|
||||
conn.close()
|
||||
|
||||
@pytest.fixture
|
||||
def spy_dcu_cmd():
|
||||
conn = SolarmanV5(None, ('test.local', 1234), server_side=True, client_mode= False, ifc=AsyncIfcImpl())
|
||||
conn.node_id = 'inv_3/'
|
||||
with patch.object(conn, 'send_dcu_cmd', wraps=conn.send_dcu_cmd) as wrapped_conn:
|
||||
yield wrapped_conn
|
||||
conn.close()
|
||||
|
||||
def test_native_client(test_hostname, test_port):
|
||||
"""Sanity check: Make sure the paho-mqtt client can connect to the test
|
||||
MQTT server. Otherwise the test set NO_MOSQUITTO_TEST to True and disable
|
||||
@@ -134,6 +96,7 @@ def test_native_client(test_hostname, test_port):
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mqtt_connection(config_mqtt_conn):
|
||||
global NO_MOSQUITTO_TEST
|
||||
if NO_MOSQUITTO_TEST:
|
||||
pytest.skip('skipping, since Mosquitto is not reliable at the moment')
|
||||
|
||||
@@ -159,6 +122,7 @@ async def test_mqtt_connection(config_mqtt_conn):
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_ha_reconnect(config_mqtt_conn):
|
||||
global NO_MOSQUITTO_TEST
|
||||
if NO_MOSQUITTO_TEST:
|
||||
pytest.skip('skipping, since Mosquitto is not reliable at the moment')
|
||||
|
||||
@@ -178,21 +142,16 @@ async def test_ha_reconnect(config_mqtt_conn):
|
||||
assert on_connect.is_set()
|
||||
|
||||
finally:
|
||||
assert m.received == 2
|
||||
await m.close()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mqtt_no_config(config_no_conn, monkeypatch):
|
||||
async def test_mqtt_no_config(config_no_conn):
|
||||
_ = config_no_conn
|
||||
assert asyncio.get_running_loop()
|
||||
|
||||
on_connect = asyncio.Event()
|
||||
async def cb():
|
||||
on_connect.set()
|
||||
async def my_publish(*args):
|
||||
return
|
||||
|
||||
monkeypatch.setattr(aiomqtt.Client, "publish", my_publish)
|
||||
|
||||
try:
|
||||
m = Mqtt(cb)
|
||||
@@ -201,193 +160,74 @@ async def test_mqtt_no_config(config_no_conn, monkeypatch):
|
||||
assert not on_connect.is_set()
|
||||
try:
|
||||
await m.publish('homeassistant/status', 'online')
|
||||
assert m.published == 1
|
||||
assert False
|
||||
except Exception:
|
||||
assert False
|
||||
pass
|
||||
except TimeoutError:
|
||||
assert False
|
||||
finally:
|
||||
await m.close()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mqtt_except_no_config(config_no_conn, monkeypatch, caplog):
|
||||
_ = config_no_conn
|
||||
|
||||
assert asyncio.get_running_loop()
|
||||
|
||||
async def my_aenter(self):
|
||||
raise MqttError('TestException') from None
|
||||
|
||||
monkeypatch.setattr(aiomqtt.Client, "__aenter__", my_aenter)
|
||||
|
||||
LOGGER = logging.getLogger("mqtt")
|
||||
LOGGER.propagate = True
|
||||
LOGGER.setLevel(logging.INFO)
|
||||
|
||||
with caplog.at_level(logging.INFO):
|
||||
m = Mqtt(None)
|
||||
assert m.task
|
||||
await asyncio.sleep(0)
|
||||
try:
|
||||
await m.publish('homeassistant/status', 'online')
|
||||
assert False
|
||||
except MqttError:
|
||||
pass
|
||||
except Exception:
|
||||
assert False
|
||||
finally:
|
||||
await m.close()
|
||||
assert 'Connection lost; Reconnecting in 5 seconds' in caplog.text
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mqtt_except_def_config(config_def_conn, monkeypatch, caplog):
|
||||
_ = config_def_conn
|
||||
|
||||
assert asyncio.get_running_loop()
|
||||
|
||||
on_connect = asyncio.Event()
|
||||
async def cb():
|
||||
on_connect.set()
|
||||
|
||||
async def my_aenter(self):
|
||||
raise MqttError('TestException') from None
|
||||
|
||||
monkeypatch.setattr(aiomqtt.Client, "__aenter__", my_aenter)
|
||||
|
||||
LOGGER = logging.getLogger("mqtt")
|
||||
LOGGER.propagate = True
|
||||
LOGGER.setLevel(logging.INFO)
|
||||
|
||||
with caplog.at_level(logging.INFO):
|
||||
m = Mqtt(cb)
|
||||
assert m.task
|
||||
await asyncio.sleep(0)
|
||||
assert not on_connect.is_set()
|
||||
try:
|
||||
await m.publish('homeassistant/status', 'online')
|
||||
assert False
|
||||
except MqttError:
|
||||
pass
|
||||
except Exception:
|
||||
assert False
|
||||
finally:
|
||||
await m.close()
|
||||
assert 'MQTT is unconfigured; Check your config.toml!' in caplog.text
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mqtt_dispatch(config_mqtt_conn, aiomqtt_mock, spy_modbus_cmd):
|
||||
async def test_msg_dispatch(config_mqtt_conn, spy_modbus_cmd):
|
||||
_ = config_mqtt_conn
|
||||
_ = aiomqtt_mock
|
||||
spy = spy_modbus_cmd
|
||||
try:
|
||||
m = Mqtt(None)
|
||||
assert m.ha_restarts == 0
|
||||
await m.receive('homeassistant/status', b'online') # send the message
|
||||
assert m.ha_restarts == 1
|
||||
|
||||
await m.receive(topic= 'tsun/inv_1/rated_load', payload= b'2')
|
||||
spy.assert_called_once_with(Modbus.WRITE_SINGLE_REG, 0x2008, 2, logging.INFO)
|
||||
|
||||
spy.reset_mock()
|
||||
await m.receive(topic= 'tsun/inv_1/out_coeff', payload= b'100')
|
||||
spy.assert_called_once_with(Modbus.WRITE_SINGLE_REG, 0x202c, 1024, logging.INFO)
|
||||
msg = aiomqtt.Message(topic= 'tsun/inv_1/rated_load', payload= b'2', qos= 0, retain = False, mid= 0, properties= None)
|
||||
await m.dispatch_msg(msg)
|
||||
spy.assert_awaited_once_with(Modbus.WRITE_SINGLE_REG, 0x2008, 2, logging.INFO)
|
||||
|
||||
spy.reset_mock()
|
||||
await m.receive(topic= 'tsun/inv_1/out_coeff', payload= b'50')
|
||||
spy.assert_called_once_with(Modbus.WRITE_SINGLE_REG, 0x202c, 512, logging.INFO)
|
||||
msg = aiomqtt.Message(topic= 'tsun/inv_1/out_coeff', payload= b'100', qos= 0, retain = False, mid= 0, properties= None)
|
||||
await m.dispatch_msg(msg)
|
||||
spy.assert_awaited_once_with(Modbus.WRITE_SINGLE_REG, 0x202c, 1024, logging.INFO)
|
||||
|
||||
spy.reset_mock()
|
||||
msg = aiomqtt.Message(topic= 'tsun/inv_1/out_coeff', payload= b'50', qos= 0, retain = False, mid= 0, properties= None)
|
||||
await m.dispatch_msg(msg)
|
||||
spy.assert_awaited_once_with(Modbus.WRITE_SINGLE_REG, 0x202c, 512, logging.INFO)
|
||||
|
||||
spy.reset_mock()
|
||||
await m.receive(topic= 'tsun/inv_1/modbus_read_regs', payload= b'0x3000, 10')
|
||||
spy.assert_called_once_with(Modbus.READ_REGS, 0x3000, 10, logging.INFO)
|
||||
msg = aiomqtt.Message(topic= 'tsun/inv_1/modbus_read_regs', payload= b'0x3000, 10', qos= 0, retain = False, mid= 0, properties= None)
|
||||
await m.dispatch_msg(msg)
|
||||
spy.assert_awaited_once_with(Modbus.READ_REGS, 0x3000, 10, logging.INFO)
|
||||
|
||||
spy.reset_mock()
|
||||
await m.receive(topic= 'tsun/inv_1/modbus_read_inputs', payload= b'0x3000, 10')
|
||||
spy.assert_called_once_with(Modbus.READ_INPUTS, 0x3000, 10, logging.INFO)
|
||||
msg = aiomqtt.Message(topic= 'tsun/inv_1/modbus_read_inputs', payload= b'0x3000, 10', qos= 0, retain = False, mid= 0, properties= None)
|
||||
await m.dispatch_msg(msg)
|
||||
spy.assert_awaited_once_with(Modbus.READ_INPUTS, 0x3000, 10, logging.INFO)
|
||||
|
||||
# test dispatching with empty mapping table
|
||||
m.topic_defs.clear()
|
||||
spy.reset_mock()
|
||||
await m.receive(topic= 'tsun/inv_1/modbus_read_inputs', payload= b'0x3000, 10')
|
||||
spy.assert_not_called()
|
||||
|
||||
# test dispatching with incomplete mapping table - invalid fnc defined
|
||||
m.topic_defs.append(
|
||||
{'prefix': 'entity_prefix', 'topic': '/+/modbus_read_inputs',
|
||||
'full_topic': 'tsun/+/modbus_read_inputs', 'fnc': 'addr'}
|
||||
)
|
||||
spy.reset_mock()
|
||||
await m.receive(topic= 'tsun/inv_1/modbus_read_inputs', payload= b'0x3000, 10')
|
||||
spy.assert_not_called()
|
||||
|
||||
except MqttError:
|
||||
assert False
|
||||
except Exception:
|
||||
assert False
|
||||
finally:
|
||||
await m.close()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mqtt_dispatch_cb(config_mqtt_conn, aiomqtt_mock):
|
||||
async def test_msg_dispatch_err(config_mqtt_conn, spy_modbus_cmd):
|
||||
_ = config_mqtt_conn
|
||||
_ = aiomqtt_mock
|
||||
|
||||
on_connect = asyncio.Event()
|
||||
async def cb():
|
||||
on_connect.set()
|
||||
try:
|
||||
m = Mqtt(cb)
|
||||
assert m.ha_restarts == 0
|
||||
await m.receive('homeassistant/status', b'online') # send the message
|
||||
assert on_connect.is_set()
|
||||
assert m.ha_restarts == 1
|
||||
|
||||
except MqttError:
|
||||
assert False
|
||||
except Exception:
|
||||
assert False
|
||||
finally:
|
||||
await m.close()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mqtt_dispatch_err(config_mqtt_conn, aiomqtt_mock, spy_modbus_cmd, caplog):
|
||||
_ = config_mqtt_conn
|
||||
_ = aiomqtt_mock
|
||||
spy = spy_modbus_cmd
|
||||
|
||||
LOGGER = logging.getLogger("mqtt")
|
||||
LOGGER.propagate = True
|
||||
LOGGER.setLevel(logging.INFO)
|
||||
|
||||
try:
|
||||
m = Mqtt(None)
|
||||
|
||||
# test out of range param
|
||||
await m.receive(topic= 'tsun/inv_1/out_coeff', payload= b'-1')
|
||||
msg = aiomqtt.Message(topic= 'tsun/inv_1/out_coeff', payload= b'-1', qos= 0, retain = False, mid= 0, properties= None)
|
||||
await m.dispatch_msg(msg)
|
||||
spy.assert_not_called()
|
||||
|
||||
# test unknown node_id
|
||||
await m.receive(topic= 'tsun/inv_2/out_coeff', payload= b'2')
|
||||
spy.reset_mock()
|
||||
msg = aiomqtt.Message(topic= 'tsun/inv_2/out_coeff', payload= b'2', qos= 0, retain = False, mid= 0, properties= None)
|
||||
await m.dispatch_msg(msg)
|
||||
spy.assert_not_called()
|
||||
|
||||
# test invalid fload param
|
||||
await m.receive(topic= 'tsun/inv_1/out_coeff', payload= b'2, 3')
|
||||
spy.assert_not_called()
|
||||
|
||||
await m.receive(topic= 'tsun/inv_1/modbus_read_regs', payload= b'0x3000, 10, 7')
|
||||
spy.reset_mock()
|
||||
msg = aiomqtt.Message(topic= 'tsun/inv_1/out_coeff', payload= b'2, 3', qos= 0, retain = False, mid= 0, properties= None)
|
||||
await m.dispatch_msg(msg)
|
||||
spy.assert_not_called()
|
||||
|
||||
await m.receive(topic= 'tsun/inv_1/dcu_power', payload= b'100W')
|
||||
spy.reset_mock()
|
||||
msg = aiomqtt.Message(topic= 'tsun/inv_1/modbus_read_regs', payload= b'0x3000, 10, 7', qos= 0, retain = False, mid= 0, properties= None)
|
||||
await m.dispatch_msg(msg)
|
||||
spy.assert_not_called()
|
||||
|
||||
with caplog.at_level(logging.INFO):
|
||||
msg = aiomqtt.Message(topic= 'tsun/inv_1/out_coeff', payload= b'2', qos= 0, retain = False, mid= 0, properties= None)
|
||||
for _ in m.each_inverter(msg, "addr"):
|
||||
pass # do nothing here
|
||||
assert 'Cmd not supported by: inv_1/' in caplog.text
|
||||
except MqttError:
|
||||
assert False
|
||||
except Exception:
|
||||
assert False
|
||||
finally:
|
||||
await m.close()
|
||||
|
||||
@@ -428,31 +268,3 @@ async def test_at_cmd_dispatch(config_mqtt_conn, spy_at_cmd):
|
||||
|
||||
finally:
|
||||
await m.close()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_dcu_dispatch(config_mqtt_conn, spy_dcu_cmd):
|
||||
_ = config_mqtt_conn
|
||||
spy = spy_dcu_cmd
|
||||
try:
|
||||
m = Mqtt(None)
|
||||
msg = aiomqtt.Message(topic= 'tsun/inv_3/dcu_power', payload= b'100.0', qos= 0, retain = False, mid= 0, properties= None)
|
||||
await m.dispatch_msg(msg)
|
||||
spy.assert_called_once_with(b'\x01\x01\x06\x01\x00\x01\x03\xe8')
|
||||
finally:
|
||||
await m.close()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_dcu_inv_value(config_mqtt_conn, spy_dcu_cmd):
|
||||
_ = config_mqtt_conn
|
||||
spy = spy_dcu_cmd
|
||||
try:
|
||||
m = Mqtt(None)
|
||||
msg = aiomqtt.Message(topic= 'tsun/inv_3/dcu_power', payload= b'99.9', qos= 0, retain = False, mid= 0, properties= None)
|
||||
await m.dispatch_msg(msg)
|
||||
spy.assert_not_called()
|
||||
|
||||
msg = aiomqtt.Message(topic= 'tsun/inv_3/dcu_power', payload= b'800.1', qos= 0, retain = False, mid= 0, properties= None)
|
||||
await m.dispatch_msg(msg)
|
||||
spy.assert_not_called()
|
||||
finally:
|
||||
await m.close()
|
||||
|
||||
@@ -3,288 +3,30 @@ import pytest
|
||||
import logging
|
||||
import os
|
||||
from mock import patch
|
||||
from server import app, Server, ProxyState, HypercornLogHndl
|
||||
from inverter_base import InverterBase
|
||||
from gen3.talent import Talent
|
||||
from server import get_log_level
|
||||
|
||||
from test_inverter_base import FakeReader, FakeWriter
|
||||
def test_get_log_level():
|
||||
|
||||
pytest_plugins = ('pytest_asyncio',)
|
||||
with patch.dict(os.environ, {}):
|
||||
log_lvl = get_log_level()
|
||||
assert log_lvl == None
|
||||
|
||||
with patch.dict(os.environ, {'LOG_LVL': 'DEBUG'}):
|
||||
log_lvl = get_log_level()
|
||||
assert log_lvl == logging.DEBUG
|
||||
|
||||
class TestServerClass:
|
||||
class FakeServer(Server):
|
||||
def __init__(self):
|
||||
pass # don't call the suoer(.__init__ for unit tests
|
||||
with patch.dict(os.environ, {'LOG_LVL': 'INFO'}):
|
||||
log_lvl = get_log_level()
|
||||
assert log_lvl == logging.INFO
|
||||
|
||||
def test_get_log_level(self):
|
||||
s = self.FakeServer()
|
||||
with patch.dict(os.environ, {'LOG_LVL': 'WARN'}):
|
||||
log_lvl = get_log_level()
|
||||
assert log_lvl == logging.WARNING
|
||||
|
||||
with patch.dict(os.environ, {}):
|
||||
log_lvl = s.get_log_level()
|
||||
assert log_lvl == None
|
||||
with patch.dict(os.environ, {'LOG_LVL': 'ERROR'}):
|
||||
log_lvl = get_log_level()
|
||||
assert log_lvl == logging.ERROR
|
||||
|
||||
with patch.dict(os.environ, {'LOG_LVL': 'DEBUG'}):
|
||||
log_lvl = s.get_log_level()
|
||||
assert log_lvl == logging.DEBUG
|
||||
|
||||
with patch.dict(os.environ, {'LOG_LVL': 'INFO'}):
|
||||
log_lvl = s.get_log_level()
|
||||
assert log_lvl == logging.INFO
|
||||
|
||||
with patch.dict(os.environ, {'LOG_LVL': 'WARN'}):
|
||||
log_lvl = s.get_log_level()
|
||||
assert log_lvl == logging.WARNING
|
||||
|
||||
with patch.dict(os.environ, {'LOG_LVL': 'ERROR'}):
|
||||
log_lvl = s.get_log_level()
|
||||
assert log_lvl == logging.ERROR
|
||||
|
||||
with patch.dict(os.environ, {'LOG_LVL': 'UNKNOWN'}):
|
||||
log_lvl = s.get_log_level()
|
||||
assert log_lvl == None
|
||||
|
||||
def test_default_args(self):
|
||||
s = self.FakeServer()
|
||||
assert s.config_path == './config/'
|
||||
assert s.json_config == ''
|
||||
assert s.toml_config == ''
|
||||
assert s.trans_path == '../translations/'
|
||||
assert s.rel_urls == False
|
||||
assert s.log_path == './log/'
|
||||
assert s.log_backups == 0
|
||||
|
||||
def test_parse_args_empty(self):
|
||||
s = self.FakeServer()
|
||||
s.parse_args([])
|
||||
assert s.config_path == './config/'
|
||||
assert s.json_config == None
|
||||
assert s.toml_config == None
|
||||
assert s.trans_path == '../translations/'
|
||||
assert s.rel_urls == False
|
||||
assert s.log_path == './log/'
|
||||
assert s.log_backups == 0
|
||||
|
||||
def test_parse_args_short(self):
|
||||
s = self.FakeServer()
|
||||
s.parse_args(['-r', '-c', '/tmp/my-config', '-j', 'cnf.jsn', '-t', 'cnf.tml', '-tr', '/my/trans/', '-l', '/my_logs/', '-b', '3'])
|
||||
assert s.config_path == '/tmp/my-config'
|
||||
assert s.json_config == 'cnf.jsn'
|
||||
assert s.toml_config == 'cnf.tml'
|
||||
assert s.trans_path == '/my/trans/'
|
||||
assert s.rel_urls == True
|
||||
assert s.log_path == '/my_logs/'
|
||||
assert s.log_backups == 3
|
||||
|
||||
def test_parse_args_long(self):
|
||||
s = self.FakeServer()
|
||||
s.parse_args(['--rel_urls', '--config_path', '/tmp/my-config', '--json_config', 'cnf.jsn',
|
||||
'--toml_config', 'cnf.tml', '--trans_path', '/my/trans/', '--log_path', '/my_logs/',
|
||||
'--log_backups', '3'])
|
||||
assert s.config_path == '/tmp/my-config'
|
||||
assert s.json_config == 'cnf.jsn'
|
||||
assert s.toml_config == 'cnf.tml'
|
||||
assert s.trans_path == '/my/trans/'
|
||||
assert s.rel_urls == True
|
||||
assert s.log_path == '/my_logs/'
|
||||
assert s.log_backups == 3
|
||||
|
||||
def test_parse_args_invalid(self):
|
||||
s = self.FakeServer()
|
||||
with pytest.raises(SystemExit) as exc_info:
|
||||
s.parse_args(['--inalid', '/tmp/my-config'])
|
||||
assert exc_info.value.code == 2
|
||||
|
||||
def test_init_logging_system(self):
|
||||
s = self.FakeServer()
|
||||
s.src_dir = 'app/src/'
|
||||
s.init_logging_system()
|
||||
assert s.log_backups == 0
|
||||
assert s.log_level == None
|
||||
assert logging.handlers.log_path == './log/'
|
||||
assert logging.handlers.log_backups == 0
|
||||
assert logging.getLogger().level == logging.DEBUG
|
||||
assert logging.getLogger('msg').level == logging.DEBUG
|
||||
assert logging.getLogger('conn').level == logging.DEBUG
|
||||
assert logging.getLogger('data').level == logging.DEBUG
|
||||
assert logging.getLogger('tracer').level == logging.INFO
|
||||
assert logging.getLogger('asyncio').level == logging.INFO
|
||||
assert logging.getLogger('hypercorn.access').level == logging.INFO
|
||||
assert logging.getLogger('hypercorn.error').level == logging.INFO
|
||||
|
||||
with patch.dict(os.environ, {'LOG_LVL': 'WARN'}):
|
||||
s.parse_args(['--log_backups', '3'])
|
||||
s.init_logging_system()
|
||||
assert s.log_backups == 3
|
||||
assert s.log_level == logging.WARNING
|
||||
assert logging.handlers.log_backups == 3
|
||||
assert logging.getLogger().level == s.log_level
|
||||
assert logging.getLogger('msg').level == s.log_level
|
||||
assert logging.getLogger('conn').level == s.log_level
|
||||
assert logging.getLogger('data').level == s.log_level
|
||||
assert logging.getLogger('tracer').level == s.log_level
|
||||
assert logging.getLogger('asyncio').level == s.log_level
|
||||
assert logging.getLogger('hypercorn.access').level == logging.INFO
|
||||
assert logging.getLogger('hypercorn.error').level == logging.INFO
|
||||
|
||||
def test_build_config_error(self, caplog):
|
||||
s = self.FakeServer()
|
||||
s.src_dir = 'app/src/'
|
||||
s.toml_config = 'app/tests/cnf/invalid_config.toml'
|
||||
|
||||
with caplog.at_level(logging.ERROR):
|
||||
s.build_config()
|
||||
assert "Can't read from app/tests/cnf/invalid_config.toml" in caplog.text
|
||||
assert "Key 'port' error:" in caplog.text
|
||||
|
||||
|
||||
class TestHypercornLogHndl:
|
||||
class FakeServer(Server):
|
||||
def __init__(self):
|
||||
pass # don't call the suoer(.__init__ for unit tests
|
||||
|
||||
def test_save_and_restore(self, capsys):
|
||||
s = self.FakeServer()
|
||||
s.src_dir = 'app/src/'
|
||||
s.init_logging_system()
|
||||
|
||||
h = HypercornLogHndl()
|
||||
assert h.must_fix == False
|
||||
assert len(h.access_hndl) == 0
|
||||
assert len(h.error_hndl) == 0
|
||||
|
||||
h.save()
|
||||
assert h.must_fix == True
|
||||
assert len(h.access_hndl) == 1
|
||||
assert len(h.error_hndl) == 2
|
||||
assert h.access_hndl == logging.getLogger('hypercorn.access').handlers
|
||||
assert h.error_hndl == logging.getLogger('hypercorn.error').handlers
|
||||
|
||||
logging.getLogger('hypercorn.access').handlers = []
|
||||
logging.getLogger('hypercorn.error').handlers = []
|
||||
|
||||
h.restore()
|
||||
assert h.must_fix == False
|
||||
assert h.access_hndl == logging.getLogger('hypercorn.access').handlers
|
||||
assert h.error_hndl == logging.getLogger('hypercorn.error').handlers
|
||||
output = capsys.readouterr().out.rstrip()
|
||||
assert "* Fix hypercorn.access setting" in output
|
||||
assert "* Fix hypercorn.error setting" in output
|
||||
|
||||
h.restore() # second restore do nothing
|
||||
assert h.must_fix == False
|
||||
output = capsys.readouterr().out.rstrip()
|
||||
assert output == ''
|
||||
|
||||
h.save() # save the same values second time
|
||||
assert h.must_fix == True
|
||||
|
||||
h.restore() # restore without changing the handlers
|
||||
assert h.must_fix == False
|
||||
output = capsys.readouterr().out.rstrip()
|
||||
assert output == ''
|
||||
|
||||
|
||||
class TestApp:
|
||||
@pytest.mark.asyncio
|
||||
async def test_ready(self):
|
||||
"""Test the ready route."""
|
||||
|
||||
ProxyState.set_up(False)
|
||||
app.testing = True
|
||||
client = app.test_client()
|
||||
response = await client.get('/-/ready')
|
||||
assert response.status_code == 503
|
||||
result = await response.get_data()
|
||||
assert result == b"Not ready"
|
||||
|
||||
ProxyState.set_up(True)
|
||||
response = await client.get('/-/ready')
|
||||
assert response.status_code == 200
|
||||
result = await response.get_data()
|
||||
assert result == b"Is ready"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_healthy(self):
|
||||
"""Test the healthy route."""
|
||||
reader = FakeReader()
|
||||
writer = FakeWriter()
|
||||
|
||||
with InverterBase(reader, writer, 'tsun', Talent):
|
||||
ProxyState.set_up(False)
|
||||
app.testing = True
|
||||
client = app.test_client()
|
||||
response = await client.get('/-/healthy')
|
||||
assert response.status_code == 200
|
||||
result = await response.get_data()
|
||||
assert result == b"I'm fine"
|
||||
|
||||
ProxyState.set_up(True)
|
||||
response = await client.get('/-/healthy')
|
||||
assert response.status_code == 200
|
||||
result = await response.get_data()
|
||||
assert result == b"I'm fine"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_unhealthy(self, monkeypatch, caplog):
|
||||
"""Test the healthy route."""
|
||||
def result_false(self):
|
||||
return False
|
||||
|
||||
LOGGER = logging.getLogger("mqtt")
|
||||
LOGGER.propagate = True
|
||||
LOGGER.setLevel(logging.INFO)
|
||||
|
||||
monkeypatch.setattr(InverterBase, "healthy", result_false)
|
||||
InverterBase._registry.clear()
|
||||
reader = FakeReader()
|
||||
writer = FakeWriter()
|
||||
|
||||
with caplog.at_level(logging.INFO) and InverterBase(reader, writer, 'tsun', Talent):
|
||||
ProxyState.set_up(False)
|
||||
app.testing = True
|
||||
client = app.test_client()
|
||||
response = await client.get('/-/healthy')
|
||||
assert response.status_code == 200
|
||||
result = await response.get_data()
|
||||
assert result == b"I'm fine"
|
||||
assert "" == caplog.text
|
||||
|
||||
ProxyState.set_up(True)
|
||||
response = await client.get('/-/healthy')
|
||||
assert response.status_code == 503
|
||||
result = await response.get_data()
|
||||
assert result == b"I have a problem"
|
||||
assert "" == caplog.text
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_healthy_exception(self, monkeypatch, caplog):
|
||||
"""Test the healthy route."""
|
||||
def result_except(self):
|
||||
raise ValueError
|
||||
|
||||
LOGGER = logging.getLogger("mqtt")
|
||||
LOGGER.propagate = True
|
||||
LOGGER.setLevel(logging.INFO)
|
||||
|
||||
monkeypatch.setattr(InverterBase, "healthy", result_except)
|
||||
InverterBase._registry.clear()
|
||||
reader = FakeReader()
|
||||
writer = FakeWriter()
|
||||
|
||||
with caplog.at_level(logging.INFO) and InverterBase(reader, writer, 'tsun', Talent):
|
||||
ProxyState.set_up(False)
|
||||
app.testing = True
|
||||
client = app.test_client()
|
||||
response = await client.get('/-/healthy')
|
||||
assert response.status_code == 200
|
||||
result = await response.get_data()
|
||||
assert result == b"I'm fine"
|
||||
assert "" == caplog.text
|
||||
|
||||
ProxyState.set_up(True)
|
||||
response = await client.get('/-/healthy')
|
||||
assert response.status_code == 200
|
||||
result = await response.get_data()
|
||||
assert result == b"I'm fine"
|
||||
assert "Exception:" in caplog.text
|
||||
with patch.dict(os.environ, {'LOG_LVL': 'UNKNOWN'}):
|
||||
log_lvl = get_log_level()
|
||||
assert log_lvl == None
|
||||
|
||||