diff --git a/ChangeLog.md b/ChangeLog.md index c7bc0a60..a830f8c1 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,12 +1,32 @@ -# 21.3 (tbd) +# 21.3 (2021-11-07) ## Bug Fixes * fix for escaping double quote in CSV format * adjusted helper shell scripts and Munin plugin to newer netcat * fix for weekday in BDA data type (for sending only) +* fix some compiler warnings +* fix non-unique message keys in HTTP JSON output with "full" query parameter +* fix for message after debian install +* fix for replacing already existing message definitions +* fix missing length in CSV dump for some data types +* fix some missing data type lengths in "grab decode" result +* fix for injecting several messages via command line args ## Features * added DTM and BDZ data types +* added "-n" argument to "hex" and "direct" commands for automatically determining message length from input +* added level/pollprio/condition/field flags and field result type as well as list of types to HTTP JSON output +* added message dump from commandline in JSON format +* added support for newer MQTT broker versions +* added some PIC calibration data to "ebuspicloader" verbose output +* added support for upcoming adapter 3 firmware enhancements +* added config override path +* added support for adding message definition, retrieving data types and raw messages, and decode data types from raw values to HTTP port +* added "--mqttverbose" option +* added verbose option to "info" command + +## Breaking Changes +* remove support for Debian 8 Jessie in docker # 21.2 (2021-02-08) diff --git a/VERSION b/VERSION index 6355495f..2b8b7b7e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -21.2 \ No newline at end of file +21.3 \ No newline at end of file diff --git a/contrib/archlinux/PKGBUILD b/contrib/archlinux/PKGBUILD index 14d81617..1bbd5d1c 100644 --- a/contrib/archlinux/PKGBUILD +++ b/contrib/archlinux/PKGBUILD @@ -2,7 +2,7 @@ # Contributor: Milan Knizek # Usage: makepkg pkgname=ebusd -pkgver=21.2 +pkgver=21.3 pkgrel=1 pkgdesc="ebusd, the daemon for communication with eBUS heating systems." arch=('i686' 'x86_64' 'armv6h' 'armv7h' 'aarch64') diff --git a/contrib/archlinux/PKGBUILD.git b/contrib/archlinux/PKGBUILD.git index 7086e074..3d6c1e83 100644 --- a/contrib/archlinux/PKGBUILD.git +++ b/contrib/archlinux/PKGBUILD.git @@ -3,7 +3,7 @@ # Usage: makepkg -p PKGBUILD.git pkgname=ebusd-git _gitname=ebusd -pkgver=21.2 +pkgver=21.3 pkgrel=1 pkgdesc="ebusd, the daemon for communication with eBUS heating systems." arch=('i686' 'x86_64' 'armv6h' 'armv7h' 'aarch64') diff --git a/contrib/docker/Dockerfile b/contrib/docker/Dockerfile index 83548677..ddd792ee 100755 --- a/contrib/docker/Dockerfile +++ b/contrib/docker/Dockerfile @@ -1,5 +1,6 @@ +ARG BASE_IMAGE -FROM debian:bullseye as build +FROM $BASE_IMAGE as build RUN apt-get update && apt-get install -y \ libmosquitto-dev libstdc++6 libc6 libgcc1 \ @@ -9,25 +10,34 @@ RUN apt-get update && apt-get install -y \ WORKDIR /build -ENV EBUSD_ARCH amd64 -ENV EBUSD_VERSION 21.2 +ARG TARGETARCH +ARG TARGETVARIANT +ARG EBUSD_VERSION -RUN git clone https://github.com/john30/ebusd.git /build \ - && ./make_debian.sh +ENV EBUSD_ARCH $TARGETARCH$TARGETVARIANT +ENV EBUSD_VERSION $EBUSD_VERSION + +ADD . /build +RUN ./make_debian.sh -FROM debian:bullseye-slim +FROM $BASE_IMAGE-slim as image RUN apt-get update && apt-get install -y \ - logrotate libmosquitto1 libstdc++6 libc6 libgcc1 \ + libmosquitto1 libstdc++6 libc6 libgcc1 \ && rm -rf /var/lib/apt/lists/* LABEL maintainer "ebusd@ebusd.eu" -ENV EBUSD_VERSION 21.2 -ENV EBUSD_ARCH amd64 +ARG TARGETARCH +ARG TARGETVARIANT +ARG EBUSD_VERSION +ARG EBUSD_IMAGE + +ENV EBUSD_ARCH $TARGETARCH$TARGETVARIANT +ENV EBUSD_VERSION $EBUSD_VERSION LABEL version "${EBUSD_VERSION}-${EBUSD_ARCH}-devel" @@ -39,6 +49,6 @@ RUN dpkg -i ebusd.deb \ EXPOSE 8888 -COPY docker-entrypoint.sh / +COPY --from=build /build/contrib/docker/docker-entrypoint.sh / ENTRYPOINT ["/docker-entrypoint.sh"] CMD ["-f", "--scanconfig"] diff --git a/contrib/docker/Dockerfile.arm32v5 b/contrib/docker/Dockerfile.arm32v5 deleted file mode 100644 index 43a0c1f3..00000000 --- a/contrib/docker/Dockerfile.arm32v5 +++ /dev/null @@ -1,42 +0,0 @@ -FROM multiarch/qemu-user-static as qemu -FROM arm32v5/debian:jessie as build -COPY --from=qemu /usr/bin/qemu-arm-static /usr/bin/ -RUN apt-get update && apt-get install -y \ - libmosquitto-dev libstdc++6 libc6 libgcc1 \ - curl \ - autoconf automake g++ make git \ - && rm -rf /var/lib/apt/lists/* -ADD . /build -WORKDIR /build - -ENV EBUSD_ARCH arm32v5 -ENV EBUSD_VERSION 21.2 - -RUN ./make_debian.sh --host `gcc -dumpmachine` - - - -FROM arm32v5/debian:jessie-slim -COPY --from=qemu /usr/bin/qemu-arm-static /usr/bin/ -RUN apt-get update && apt-get install -y \ - logrotate libmosquitto1 libstdc++6 libc6 libgcc1 \ - && rm -rf /var/lib/apt/lists/* - -LABEL maintainer "ebusd@ebusd.eu" - -ENV EBUSD_VERSION 21.2 -ENV EBUSD_ARCH arm32v5 - -LABEL version "${EBUSD_VERSION}-${EBUSD_ARCH}-devel" - -COPY --from=build /build/ebusd-*_mqtt1.deb ebusd.deb - -RUN dpkg -i ebusd.deb \ - && ebusd -V \ - && rm -f ebusd.deb /usr/bin/qemu-arm-static - -EXPOSE 8888 - -COPY --from=build /build/contrib/docker/docker-entrypoint.sh / -ENTRYPOINT ["/docker-entrypoint.sh"] -CMD ["-f", "--scanconfig"] diff --git a/contrib/docker/Dockerfile.arm32v7 b/contrib/docker/Dockerfile.arm32v7 deleted file mode 100644 index cd98bf54..00000000 --- a/contrib/docker/Dockerfile.arm32v7 +++ /dev/null @@ -1,42 +0,0 @@ -FROM multiarch/qemu-user-static as qemu -FROM arm32v7/debian:jessie as build -COPY --from=qemu /usr/bin/qemu-arm-static /usr/bin/ -RUN apt-get update && apt-get install -y \ - libmosquitto-dev libstdc++6 libc6 libgcc1 \ - curl \ - autoconf automake g++ make git \ - && rm -rf /var/lib/apt/lists/* -ADD . /build -WORKDIR /build - -ENV EBUSD_ARCH arm32v7 -ENV EBUSD_VERSION 21.2 - -RUN ./make_debian.sh - - - -FROM arm32v7/debian:jessie-slim -COPY --from=qemu /usr/bin/qemu-arm-static /usr/bin/ -RUN apt-get update && apt-get install -y \ - logrotate libmosquitto1 libstdc++6 libc6 libgcc1 \ - && rm -rf /var/lib/apt/lists/* - -LABEL maintainer "ebusd@ebusd.eu" - -ENV EBUSD_VERSION 21.2 -ENV EBUSD_ARCH arm32v7 - -LABEL version "${EBUSD_VERSION}-${EBUSD_ARCH}-devel" - -COPY --from=build /build/ebusd-*_mqtt1.deb ebusd.deb - -RUN dpkg -i ebusd.deb \ - && ebusd -V \ - && rm -f ebusd.deb /usr/bin/qemu-arm-static - -EXPOSE 8888 - -COPY --from=build /build/contrib/docker/docker-entrypoint.sh / -ENTRYPOINT ["/docker-entrypoint.sh"] -CMD ["-f", "--scanconfig"] diff --git a/contrib/docker/Dockerfile.arm64v8 b/contrib/docker/Dockerfile.arm64v8 deleted file mode 100644 index 29b0924b..00000000 --- a/contrib/docker/Dockerfile.arm64v8 +++ /dev/null @@ -1,44 +0,0 @@ -FROM multiarch/qemu-user-static as qemu -FROM arm64v8/debian:bullseye as build -COPY --from=qemu /usr/bin/qemu-aarch64-static /usr/bin/ -RUN apt-get update && apt-get install -y \ - libmosquitto-dev libstdc++6 libc6 libgcc1 \ - curl \ - autoconf automake g++ make git \ - && rm -rf /var/lib/apt/lists/* - -WORKDIR /build - -ENV EBUSD_ARCH arm64v8 -ENV EBUSD_VERSION 21.2 - -RUN git clone https://github.com/john30/ebusd.git /build \ - && ./make_debian.sh - - - - -FROM arm64v8/debian:bullseye-slim -COPY --from=qemu /usr/bin/qemu-aarch64-static /usr/bin/ -RUN apt-get update && apt-get install -y \ - logrotate libmosquitto1 libstdc++6 libc6 libgcc1 \ - && rm -rf /var/lib/apt/lists/* - -LABEL maintainer "ebusd@ebusd.eu" - -ENV EBUSD_VERSION 21.2 -ENV EBUSD_ARCH arm64v8 - -LABEL version "${EBUSD_VERSION}-${EBUSD_ARCH}-devel" - -COPY --from=build /build/ebusd-*_mqtt1.deb ebusd.deb - -RUN dpkg -i ebusd.deb \ - && ebusd -V \ - && rm -f ebusd.deb /usr/bin/qemu-aarch64-static - -EXPOSE 8888 - -COPY docker-entrypoint.sh / -ENTRYPOINT ["/docker-entrypoint.sh"] -CMD ["-f", "--scanconfig"] diff --git a/contrib/docker/Dockerfile.i386 b/contrib/docker/Dockerfile.i386 deleted file mode 100644 index 968bf03c..00000000 --- a/contrib/docker/Dockerfile.i386 +++ /dev/null @@ -1,44 +0,0 @@ -FROM multiarch/qemu-user-static as qemu -FROM i386/debian:bullseye as build -COPY --from=qemu /usr/bin/qemu-i386-static /usr/bin/ -RUN apt-get update && apt-get install -y \ - libmosquitto-dev libstdc++6 libc6 libgcc1 \ - curl \ - autoconf automake g++ make git \ - && rm -rf /var/lib/apt/lists/* - -WORKDIR /build - -ENV EBUSD_ARCH i386 -ENV EBUSD_VERSION 21.2 - -RUN git clone https://github.com/john30/ebusd.git /build \ - && ./make_debian.sh - - - - -FROM i386/debian:bullseye-slim -COPY --from=qemu /usr/bin/qemu-i386-static /usr/bin/ -RUN apt-get update && apt-get install -y \ - logrotate libmosquitto1 libstdc++6 libc6 libgcc1 \ - && rm -rf /var/lib/apt/lists/* - -LABEL maintainer "ebusd@ebusd.eu" - -ENV EBUSD_VERSION 21.2 -ENV EBUSD_ARCH i386 - -LABEL version "${EBUSD_VERSION}-${EBUSD_ARCH}-devel" - -COPY --from=build /build/ebusd-*_mqtt1.deb ebusd.deb - -RUN dpkg -i ebusd.deb \ - && ebusd -V \ - && rm -f ebusd.deb /usr/bin/qemu-i386-static - -EXPOSE 8888 - -COPY docker-entrypoint.sh / -ENTRYPOINT ["/docker-entrypoint.sh"] -CMD ["-f", "--scanconfig"] diff --git a/contrib/docker/Dockerfile.release b/contrib/docker/Dockerfile.release index 8e94afb8..b76deba5 100644 --- a/contrib/docker/Dockerfile.release +++ b/contrib/docker/Dockerfile.release @@ -1,5 +1,6 @@ +ARG BASE_IMAGE -FROM debian:bullseye as build +FROM $BASE_IMAGE as build RUN apt-get update && apt-get install -y \ libmosquitto-dev libstdc++6 libc6 libgcc1 \ @@ -9,29 +10,38 @@ RUN apt-get update && apt-get install -y \ WORKDIR /build -ENV EBUSD_ARCH amd64 -ENV EBUSD_VERSION 21.2 +ARG TARGETARCH +ARG TARGETVARIANT +ARG EBUSD_VERSION -RUN git clone https://github.com/john30/ebusd.git /build \ - && ./make_debian.sh +ENV EBUSD_ARCH $TARGETARCH$TARGETVARIANT +ENV EBUSD_VERSION $EBUSD_VERSION + +ADD . /build +RUN ./make_debian.sh -FROM debian:bullseye-slim +FROM $BASE_IMAGE-slim as image RUN apt-get update && apt-get install -y \ - logrotate libmosquitto1 libstdc++6 libc6 libgcc1 \ + libmosquitto1 libstdc++6 libc6 libgcc1 \ && rm -rf /var/lib/apt/lists/* LABEL maintainer "ebusd@ebusd.eu" -ENV EBUSD_VERSION 21.2 -ENV EBUSD_ARCH amd64 +ARG TARGETARCH +ARG TARGETVARIANT +ARG EBUSD_VERSION +ARG EBUSD_IMAGE + +ENV EBUSD_ARCH $TARGETARCH$TARGETVARIANT +ENV EBUSD_VERSION $EBUSD_VERSION LABEL version "${EBUSD_VERSION}-${EBUSD_ARCH}" -COPY --from=build /build/ebusd-*_mqtt1.deb ebusd.deb +ADD https://github.com/john30/ebusd/releases/download/v${EBUSD_VERSION}/ebusd-${EBUSD_VERSION}_${TARGETARCH}${TARGETVARIANT}-${EBUSD_IMAGE}_mqtt1.deb ebusd.deb RUN dpkg -i ebusd.deb \ && ebusd -V \ @@ -39,6 +49,6 @@ RUN dpkg -i ebusd.deb \ EXPOSE 8888 -COPY docker-entrypoint.sh / +COPY contrib/docker/docker-entrypoint.sh / ENTRYPOINT ["/docker-entrypoint.sh"] CMD ["-f", "--scanconfig"] diff --git a/contrib/docker/Dockerfile.release.arm32v5 b/contrib/docker/Dockerfile.release.arm32v5 deleted file mode 100644 index 67979710..00000000 --- a/contrib/docker/Dockerfile.release.arm32v5 +++ /dev/null @@ -1,44 +0,0 @@ -FROM multiarch/qemu-user-static as qemu -FROM arm32v5/debian:bullseye as build -COPY --from=qemu /usr/bin/qemu-arm-static /usr/bin/ -RUN apt-get update && apt-get install -y \ - libmosquitto-dev libstdc++6 libc6 libgcc1 \ - curl \ - autoconf automake g++ make git \ - && rm -rf /var/lib/apt/lists/* - -WORKDIR /build - -ENV EBUSD_ARCH arm32v5 -ENV EBUSD_VERSION 21.2 - -RUN git clone https://github.com/john30/ebusd.git /build \ - && ./make_debian.sh - - - - -FROM arm32v5/debian:bullseye-slim -COPY --from=qemu /usr/bin/qemu-arm-static /usr/bin/ -RUN apt-get update && apt-get install -y \ - logrotate libmosquitto1 libstdc++6 libc6 libgcc1 \ - && rm -rf /var/lib/apt/lists/* - -LABEL maintainer "ebusd@ebusd.eu" - -ENV EBUSD_VERSION 21.2 -ENV EBUSD_ARCH arm32v5 - -LABEL version "${EBUSD_VERSION}-${EBUSD_ARCH}" - -COPY --from=build /build/ebusd-*_mqtt1.deb ebusd.deb - -RUN dpkg -i ebusd.deb \ - && ebusd -V \ - && rm -f ebusd.deb /usr/bin/qemu-arm-static - -EXPOSE 8888 - -COPY docker-entrypoint.sh / -ENTRYPOINT ["/docker-entrypoint.sh"] -CMD ["-f", "--scanconfig"] diff --git a/contrib/docker/Dockerfile.release.arm32v7 b/contrib/docker/Dockerfile.release.arm32v7 deleted file mode 100644 index 733f26ce..00000000 --- a/contrib/docker/Dockerfile.release.arm32v7 +++ /dev/null @@ -1,44 +0,0 @@ -FROM multiarch/qemu-user-static as qemu -FROM arm32v7/debian:bullseye as build -COPY --from=qemu /usr/bin/qemu-arm-static /usr/bin/ -RUN apt-get update && apt-get install -y \ - libmosquitto-dev libstdc++6 libc6 libgcc1 \ - curl \ - autoconf automake g++ make git \ - && rm -rf /var/lib/apt/lists/* - -WORKDIR /build - -ENV EBUSD_ARCH arm32v7 -ENV EBUSD_VERSION 21.2 - -RUN git clone https://github.com/john30/ebusd.git /build \ - && ./make_debian.sh - - - - -FROM arm32v7/debian:bullseye-slim -COPY --from=qemu /usr/bin/qemu-arm-static /usr/bin/ -RUN apt-get update && apt-get install -y \ - logrotate libmosquitto1 libstdc++6 libc6 libgcc1 \ - && rm -rf /var/lib/apt/lists/* - -LABEL maintainer "ebusd@ebusd.eu" - -ENV EBUSD_VERSION 21.2 -ENV EBUSD_ARCH arm32v7 - -LABEL version "${EBUSD_VERSION}-${EBUSD_ARCH}" - -COPY --from=build /build/ebusd-*_mqtt1.deb ebusd.deb - -RUN dpkg -i ebusd.deb \ - && ebusd -V \ - && rm -f ebusd.deb /usr/bin/qemu-arm-static - -EXPOSE 8888 - -COPY docker-entrypoint.sh / -ENTRYPOINT ["/docker-entrypoint.sh"] -CMD ["-f", "--scanconfig"] diff --git a/contrib/docker/Dockerfile.release.arm64v8 b/contrib/docker/Dockerfile.release.arm64v8 deleted file mode 100644 index a9519e56..00000000 --- a/contrib/docker/Dockerfile.release.arm64v8 +++ /dev/null @@ -1,44 +0,0 @@ -FROM multiarch/qemu-user-static as qemu -FROM arm64v8/debian:bullseye as build -COPY --from=qemu /usr/bin/qemu-aarch64-static /usr/bin/ -RUN apt-get update && apt-get install -y \ - libmosquitto-dev libstdc++6 libc6 libgcc1 \ - curl \ - autoconf automake g++ make git \ - && rm -rf /var/lib/apt/lists/* - -WORKDIR /build - -ENV EBUSD_ARCH arm64v8 -ENV EBUSD_VERSION 21.2 - -RUN git clone https://github.com/john30/ebusd.git /build \ - && ./make_debian.sh - - - - -FROM arm64v8/debian:bullseye-slim -COPY --from=qemu /usr/bin/qemu-aarch64-static /usr/bin/ -RUN apt-get update && apt-get install -y \ - logrotate libmosquitto1 libstdc++6 libc6 libgcc1 \ - && rm -rf /var/lib/apt/lists/* - -LABEL maintainer "ebusd@ebusd.eu" - -ENV EBUSD_VERSION 21.2 -ENV EBUSD_ARCH arm64v8 - -LABEL version "${EBUSD_VERSION}-${EBUSD_ARCH}" - -COPY --from=build /build/ebusd-*_mqtt1.deb ebusd.deb - -RUN dpkg -i ebusd.deb \ - && ebusd -V \ - && rm -f ebusd.deb /usr/bin/qemu-aarch64-static - -EXPOSE 8888 - -COPY docker-entrypoint.sh / -ENTRYPOINT ["/docker-entrypoint.sh"] -CMD ["-f", "--scanconfig"] diff --git a/contrib/docker/Dockerfile.release.i386 b/contrib/docker/Dockerfile.release.i386 deleted file mode 100644 index a2a0de05..00000000 --- a/contrib/docker/Dockerfile.release.i386 +++ /dev/null @@ -1,44 +0,0 @@ -FROM multiarch/qemu-user-static as qemu -FROM i386/debian:bullseye as build -COPY --from=qemu /usr/bin/qemu-i386-static /usr/bin/ -RUN apt-get update && apt-get install -y \ - libmosquitto-dev libstdc++6 libc6 libgcc1 \ - curl \ - autoconf automake g++ make git \ - && rm -rf /var/lib/apt/lists/* - -WORKDIR /build - -ENV EBUSD_ARCH i386 -ENV EBUSD_VERSION 21.2 - -RUN git clone https://github.com/john30/ebusd.git /build \ - && ./make_debian.sh - - - - -FROM i386/debian:bullseye-slim -COPY --from=qemu /usr/bin/qemu-i386-static /usr/bin/ -RUN apt-get update && apt-get install -y \ - logrotate libmosquitto1 libstdc++6 libc6 libgcc1 \ - && rm -rf /var/lib/apt/lists/* - -LABEL maintainer "ebusd@ebusd.eu" - -ENV EBUSD_VERSION 21.2 -ENV EBUSD_ARCH i386 - -LABEL version "${EBUSD_VERSION}-${EBUSD_ARCH}" - -COPY --from=build /build/ebusd-*_mqtt1.deb ebusd.deb - -RUN dpkg -i ebusd.deb \ - && ebusd -V \ - && rm -f ebusd.deb /usr/bin/qemu-i386-static - -EXPOSE 8888 - -COPY docker-entrypoint.sh / -ENTRYPOINT ["/docker-entrypoint.sh"] -CMD ["-f", "--scanconfig"] diff --git a/contrib/docker/Dockerfile.template b/contrib/docker/Dockerfile.template index ddf4a740..2d5f1aee 100644 --- a/contrib/docker/Dockerfile.template +++ b/contrib/docker/Dockerfile.template @@ -1,6 +1,7 @@ -%QEMU_FROM_LINE% -FROM %BASE_IMAGE% as build -%QEMU_FROM_COPY% +ARG BASE_IMAGE + +FROM $BASE_IMAGE as build + RUN apt-get update && apt-get install -y \ libmosquitto-dev libstdc++6 libc6 libgcc1 \ curl \ @@ -9,36 +10,45 @@ RUN apt-get update && apt-get install -y \ WORKDIR /build -ENV EBUSD_ARCH %EBUSD_ARCH% -ENV EBUSD_VERSION %EBUSD_VERSION% +ARG TARGETARCH +ARG TARGETVARIANT +ARG EBUSD_VERSION -RUN git clone https://github.com/john30/ebusd.git /build \ - && %EBUSD_MAKE% +ENV EBUSD_ARCH $TARGETARCH$TARGETVARIANT +ENV EBUSD_VERSION $EBUSD_VERSION + +ADD . /build +RUN %EBUSD_MAKE% %EBUSD_UPLOAD_LINES% -FROM %BASE_IMAGE%-slim -%QEMU_FROM_COPY% +FROM $BASE_IMAGE-slim as image + RUN apt-get update && apt-get install -y \ - logrotate libmosquitto1 libstdc++6 libc6 libgcc1 \ + libmosquitto1 libstdc++6 libc6 libgcc1 \ && rm -rf /var/lib/apt/lists/* LABEL maintainer "ebusd@ebusd.eu" -ENV EBUSD_VERSION %EBUSD_VERSION% -ENV EBUSD_ARCH %EBUSD_ARCH% +ARG TARGETARCH +ARG TARGETVARIANT +ARG EBUSD_VERSION +ARG EBUSD_IMAGE + +ENV EBUSD_ARCH $TARGETARCH$TARGETVARIANT +ENV EBUSD_VERSION $EBUSD_VERSION LABEL version "${EBUSD_VERSION}-${EBUSD_ARCH}%EBUSD_VERSION_VARIANT%" -COPY --from=build /build/ebusd-*_mqtt1.deb ebusd.deb +%EBUSD_COPYDEB% RUN dpkg -i ebusd.deb \ && ebusd -V \ - && rm -f ebusd.deb%EXTRA_RM% + && rm -f ebusd.deb EXPOSE 8888 -COPY docker-entrypoint.sh / +%EBUSD_COPYENTRY% ENTRYPOINT ["/docker-entrypoint.sh"] CMD ["-f", "--scanconfig"] diff --git a/contrib/docker/README.md b/contrib/docker/README.md index e8230073..1f959a86 100644 --- a/contrib/docker/README.md +++ b/contrib/docker/README.md @@ -2,8 +2,8 @@ ebusd Docker image ================== An [ebusd](https://github.com/john30/ebusd/) Docker image is available on the -[Docker Hub](https://hub.docker.com/r/john30/ebusd/) and comes with the latest German -[configuration files](https://github.com/john30/ebusd-configuration/). +[Docker Hub](https://hub.docker.com/r/john30/ebusd/) and is able to download the latest released German +[configuration files](https://github.com/john30/ebusd-configuration/) from a dedicated webservice. It allows you to run ebusd without actually installing (or even building) it on your system. You might even be able to run it on a non-Linux operating system, which is at least known to @@ -18,12 +18,11 @@ To download the latest release image from the hub, use the following command: The image is able to run on any of the following architectures and the right image will be picked automatically: * amd64 * i386 -* arm32v5 * arm32v7 * arm64v8 -In addition to the default "latest" tag, a development set of images is available with "devel" tag. This is built -automatically with every commit to the git repository. Run the following command to use it: +Due to changes of docker hub policies, the development set of images with "devel" tag are currently not automatically +built with every commit to the git repository. Run the following command to use it: > docker pull john30/ebusd:devel @@ -54,9 +53,9 @@ Using a network device When using a network device, the "--device" argument to docker can be omitted, but the device information has to be passed on to ebusd: -> docker run --rm -it -p 8888 john30/ebusd -f --scanconfig -d udp:192.168.178.123:10000 --latency=80 +> docker run --rm -it -p 8888 john30/ebusd -f --scanconfig -d 192.168.178.123:10000 --latency=20 -Note: the "-f" and "--scanconfig" arguments are only passed to ebusd if it is called without any additional arguments. +Note: the default "-f" and "--scanconfig" arguments are only passed to ebusd if it is called without any additional arguments. So when passing further arguments, these two usually need to be added as well. diff --git a/contrib/docker/build.sh b/contrib/docker/build.sh index 94519dc1..f7a32aab 100755 --- a/contrib/docker/build.sh +++ b/contrib/docker/build.sh @@ -1,20 +1,55 @@ #!/bin/bash -archs='amd64 i386 arm32v5 arm32v7 arm64v8' -images='stretch buster bullseye' -UPLOAD_URL='http://'`hostname`'/ebusdreleaseupload.php' +if [[ -z "$1" ]]; then + echo "usage: $0 [release|UPLOADHOST]" + echo " without arguments: build and push devel docker images" + echo " release: build and push release docker images from latest release binaries" + echo " UPLOADHOST: build Debian release packages (with and without MQTT) and upload them to UPLOADHOST" + exit 1 +fi +archs=linux/amd64,linux/386,linux/arm/v7,linux/arm64 +if [[ -z "$1" ]] || [[ "x$1" == "xrelease" ]]; then + UPLOAD_URL= +else + UPLOAD_URL="http://$1/ebusdreleaseupload.php" +fi UPLOAD_CREDENTIALS='anonymous:build' -for image in $images; do - dir=$image - mkdir -p $dir - BASE_IMAGE=debian:$image ./update.sh $dir/ - for arch in $archs; do - if [ "$arch" != "amd64" ]; then - suffix=".$arch" - else - suffix='' - fi - docker build $@ --target build --build-arg "UPLOAD_URL=$UPLOAD_URL" --build-arg "UPLOAD_CREDENTIALS=$UPLOAD_CREDENTIALS" --build-arg "UPLOAD_OS=$image" -f $dir/Dockerfile$suffix . - done - rm -rf $dir -done +version=`cat ../../VERSION` +source='../..' +images='bullseye' +if [[ -z "$1" ]]; then + namesuffix='' + target=image + outputFmt='-o type=docker,type=registry' + tagsuffix=':devel' +elif [[ "x$1" = "xrelease" ]]; then + archs=linux/amd64 + namesuffix='.release' + target=image + outputFmt='-o type=docker,type=registry' + tagsuffix=":v$version" +else + namesuffix='.build' + target=build + images='bullseye buster stretch' + outputFmt=-q + tagsuffix=":v$version-prep" +fi + +for image in $images; do + output=$(echo "$outputFmt"|sed -e "s#%IMAGE%#$image#g") + docker buildx build \ + --target $target \ + --progress pain \ + --platform $archs \ + -f Dockerfile${namesuffix} \ + --build-arg "BASE_IMAGE=debian:$image" \ + --build-arg "EBUSD_VERSION=$version" \ + --build-arg "EBUSD_IMAGE=$image" \ + --build-arg "UPLOAD_URL=$UPLOAD_URL" \ + --build-arg "UPLOAD_CREDENTIALS=$UPLOAD_CREDENTIALS" \ + --build-arg "UPLOAD_OS=$image" \ + -t ebusd$tagsuffix \ + $output \ + $source +done diff --git a/contrib/docker/update.sh b/contrib/docker/update.sh index e78d4830..224ea2af 100755 --- a/contrib/docker/update.sh +++ b/contrib/docker/update.sh @@ -1,63 +1,37 @@ #!/bin/bash -DEFAULT_IMAGE=debian:bullseye -EBUSD_VERSION=`cat ../../VERSION` - -archs='amd64 i386 arm32v5:arm arm32v7:arm arm64v8:aarch64' function replaceTemplate () { - prefix= - suffix= - qemu_from_line= - qemu_from_copy= - extra_rm= - if [ "$arch" != "amd64" ]; then - qemu="${arch##*:}" - arch="${arch%%:*}" - prefix="$arch/" - suffix=".$arch" - qemu_from_line="FROM multiarch/qemu-user-static as qemu" - qemu_from_copy="COPY --from=qemu /usr/bin/qemu-$qemu-static /usr/bin/" - extra_rm=" /usr/bin/qemu-$qemu-static" - fi - file="${dir}Dockerfile${namesuffix}${suffix}" + file="Dockerfile${namesuffix}" sed \ - -e "s#%QEMU_FROM_LINE%#${qemu_from_line}#g" \ - -e "s#%BASE_IMAGE%#${prefix}${BASE_IMAGE:-$DEFAULT_IMAGE}#g" \ - -e "s#%QEMU_FROM_COPY%#${qemu_from_copy}#g" \ -e "s#%EBUSD_MAKE%#${make}#g" \ - -e "s#%EBUSD_VERSION%#${EBUSD_VERSION}#g" \ -e "s#%EBUSD_VERSION_VARIANT%#${version_variant}#g" \ - -e "s#%EBUSD_ARCH%#${arch}#g" \ - -e "s#%EXTRA_RM%#${extra_rm}#g" \ -e "s#%EBUSD_UPLOAD_LINES%#${upload_lines}#g" \ + -e "s#%EBUSD_COPYDEB%#${copydeb}#g" \ + -e "s#%EBUSD_COPYENTRY%#${copyentry}#g" \ Dockerfile.template > "$file" echo "updated $file" } -if [[ -z "$1" ]]; then - # devel updates - version_variant='-devel' - make='./make_debian.sh' - dir='' - upload_line='' - namesuffix='' - for arch in $archs; do - replaceTemplate - done -fi +# devel update +version_variant='-devel' +make='./make_debian.sh' +upload_lines='' +copydeb='COPY --from=build /build/ebusd-*_mqtt1.deb ebusd.deb' +copyentry='COPY --from=build /build/contrib/docker/docker-entrypoint.sh /' +namesuffix='' +replaceTemplate -# release updates +# release update version_variant='' -dir="$1" +copydeb="ADD https://github.com/john30/ebusd/releases/download/v\${EBUSD_VERSION}/ebusd-\${EBUSD_VERSION}_\${TARGETARCH}\${TARGETVARIANT}-\${EBUSD_IMAGE}_mqtt1.deb ebusd.deb" +copyentry='COPY contrib/docker/docker-entrypoint.sh /' +namesuffix='.release' +replaceTemplate + if [[ -n "$1" ]]; then + # build releases update make='./make_all.sh' upload_lines='ARG UPLOAD_URL\nARG UPLOAD_CREDENTIALS\nARG UPLOAD_OS\nRUN if [ -n "\$UPLOAD_URL" ] \&\& [ -n "\$UPLOAD_CREDENTIALS" ]; then for img in ebusd-*.deb; do echo -n "upload \$img: "; curl -fs -u "\$UPLOAD_CREDENTIALS" -X POST --data-binary "@\$img" -H "Content-Type: application/octet-stream" "\$UPLOAD_URL/\$img?a=\$EBUSD_ARCH\&o=\$UPLOAD_OS\&v=\$EBUSD_VERSION" || echo "failed"; done; fi' - namesuffix='' -else - make='./make_debian.sh' - namesuffix='.release' -fi -for arch in $archs; do + namesuffix='.build' replaceTemplate -done - +fi diff --git a/contrib/html/openapi.yaml b/contrib/html/openapi.yaml index 39d933f9..e8889e0a 100644 --- a/contrib/html/openapi.yaml +++ b/contrib/html/openapi.yaml @@ -10,86 +10,19 @@ paths: get: summary: Get all messages of all circuits. parameters: - - name: since - in: query - description: limit to messages that have changed since the specified UTC seconds. - allowEmptyValue: false - schema: - minimum: 0 - type: integer - - name: poll - in: query - description: set the poll priority of matching message(s) to prio. - allowEmptyValue: false - schema: - minimum: 0 - type: integer - - name: verbose - in: query - description: include comments and field units. - allowEmptyValue: false - schema: - type: boolean - - name: indexed - in: query - description: always return field indexes instead of names. - allowEmptyValue: false - schema: - type: boolean - - name: numeric - in: query - description: return numeric values of value list entries. - allowEmptyValue: false - schema: - type: boolean - - name: valuename - in: query - description: include value and name for named values. - allowEmptyValue: false - schema: - type: boolean - - name: full - in: query - description: include all available attributes. - allowEmptyValue: false - schema: - type: boolean - - name: required - in: query - description: retrieve the data from the bus if not yet cached. - allowEmptyValue: false - schema: - type: boolean - - name: write - in: query - description: retrieve write messages in addition to read/poll messages. - allowEmptyValue: false - schema: - type: boolean - - name: raw - in: query - description: include raw master/slave data. - allowEmptyValue: false - schema: - type: boolean - - name: def - in: query - description: include message and field definition. - allowEmptyValue: false - schema: - type: boolean - - name: user - in: query - description: authenticate with user name. - allowEmptyValue: false - schema: - type: string - - name: secret - in: query - description: authenticate with user secret. - allowEmptyValue: false - schema: - type: string + - $ref: '#/components/parameters/sinceQuery' + - $ref: '#/components/parameters/pollQuery' + - $ref: '#/components/parameters/verboseQuery' + - $ref: '#/components/parameters/indexedQuery' + - $ref: '#/components/parameters/numericQuery' + - $ref: '#/components/parameters/valuenameQuery' + - $ref: '#/components/parameters/fullQuery' + - $ref: '#/components/parameters/requiredQuery' + - $ref: '#/components/parameters/writeQuery' + - $ref: '#/components/parameters/rawQuery' + - $ref: '#/components/parameters/defQuery' + - $ref: '#/components/parameters/userQuery' + - $ref: '#/components/parameters/secretQuery' responses: 200: description: Success. @@ -118,92 +51,20 @@ paths: required: true schema: type: string - - name: since - in: query - description: limit to messages that have changed since the specified UTC seconds. - allowEmptyValue: false - schema: - minimum: 0 - type: integer - - name: poll - in: query - description: set the poll priority of matching message(s) to prio. - allowEmptyValue: false - schema: - minimum: 0 - type: integer - - name: exact - in: query - description: exact search for circuit/message name. - allowEmptyValue: false - schema: - type: boolean - - name: verbose - in: query - description: include comments and field units. - allowEmptyValue: false - schema: - type: boolean - - name: indexed - in: query - description: always return field indexes instead of names. - allowEmptyValue: false - schema: - type: boolean - - name: numeric - in: query - description: return numeric values of value list entries. - allowEmptyValue: false - schema: - type: boolean - - name: valuename - in: query - description: include value and name for named values. - allowEmptyValue: false - schema: - type: boolean - - name: full - in: query - description: include all available attributes. - allowEmptyValue: false - schema: - type: boolean - - name: required - in: query - description: retrieve the data from the bus if not yet cached. - allowEmptyValue: false - schema: - type: boolean - - name: write - in: query - description: retrieve write messages in addition to read/poll messages. - allowEmptyValue: false - schema: - type: boolean - - name: raw - in: query - description: include raw master/slave data. - allowEmptyValue: false - schema: - type: boolean - - name: def - in: query - description: include message and field definition. - allowEmptyValue: false - schema: - type: boolean - - name: user - in: query - description: authenticate with user name. - allowEmptyValue: false - schema: - type: string - - name: secret - in: query - description: authenticate with user secret. - allowEmptyValue: false - schema: - type: string + - $ref: '#/components/parameters/sinceQuery' + - $ref: '#/components/parameters/pollQuery' + - $ref: '#/components/parameters/exactQuery' + - $ref: '#/components/parameters/verboseQuery' + - $ref: '#/components/parameters/indexedQuery' + - $ref: '#/components/parameters/numericQuery' + - $ref: '#/components/parameters/valuenameQuery' + - $ref: '#/components/parameters/fullQuery' + - $ref: '#/components/parameters/requiredQuery' + - $ref: '#/components/parameters/writeQuery' + - $ref: '#/components/parameters/rawQuery' + - $ref: '#/components/parameters/defQuery' + - $ref: '#/components/parameters/userQuery' + - $ref: '#/components/parameters/secretQuery' responses: 200: description: Success. @@ -237,92 +98,21 @@ paths: required: true schema: type: string - - name: since - in: query - description: limit to messages that have changed since the specified UTC seconds. - allowEmptyValue: false - schema: - minimum: 0 - type: integer - - name: poll - in: query - description: set the poll priority of matching message(s) to prio. - allowEmptyValue: false - schema: - minimum: 0 - type: integer - - name: exact - in: query - description: exact search for circuit/message name. - allowEmptyValue: false - schema: - type: boolean - - name: verbose - in: query - description: include comments and field units. - allowEmptyValue: false - schema: - type: boolean - - name: indexed - in: query - description: always return field indexes instead of names. - allowEmptyValue: false - schema: - type: boolean - - name: numeric - in: query - description: return numeric values of value list entries. - allowEmptyValue: false - schema: - type: boolean - - name: valuename - in: query - description: include value and name for named values. - allowEmptyValue: false - schema: - type: boolean - - name: full - in: query - description: include all available attributes. - allowEmptyValue: false - schema: - type: boolean - - name: required - in: query - description: retrieve the data from the bus if not yet cached. - allowEmptyValue: false - schema: - type: boolean - - name: write - in: query - description: retrieve write messages in addition to read/poll messages. - allowEmptyValue: false - schema: - type: boolean - - name: raw - in: query - description: include raw master/slave data. - allowEmptyValue: false - schema: - type: boolean - - name: def - in: query - description: include message and field definition. - allowEmptyValue: false - schema: - type: boolean - - name: user - in: query - description: authenticate with user name. - allowEmptyValue: false - schema: - type: string - - name: secret - in: query - description: authenticate with user secret. - allowEmptyValue: false - schema: - type: string + - $ref: '#/components/parameters/sinceQuery' + - $ref: '#/components/parameters/pollQuery' + - $ref: '#/components/parameters/exactQuery' + - $ref: '#/components/parameters/verboseQuery' + - $ref: '#/components/parameters/indexedQuery' + - $ref: '#/components/parameters/numericQuery' + - $ref: '#/components/parameters/valuenameQuery' + - $ref: '#/components/parameters/fullQuery' + - $ref: '#/components/parameters/requiredQuery' + - $ref: '#/components/parameters/writeQuery' + - $ref: '#/components/parameters/rawQuery' + - $ref: '#/components/parameters/defQuery' + - $ref: '#/components/parameters/defineQuery' + - $ref: '#/components/parameters/userQuery' + - $ref: '#/components/parameters/secretQuery' responses: 200: description: Success @@ -333,6 +123,66 @@ paths: 500: description: Circuit or message not found. content: { } + /datatypes: + get: + summary: Get all known field data types. + responses: + 200: + description: Success. + content: + application/json;charset=utf-8: + schema: + $ref: '#/components/schemas/DataTypes' + 400: + description: Invalid request parameters. + content: { } + 403: + description: User not authorized. + content: { } + 404: + description: Circuit or message not found. + content: { } + 500: + description: General error. + content: { } + /raw: + get: + summary: Retrieve raw data from grabbed and/or decoded messages. + parameters: + - $ref: '#/components/parameters/sinceQuery' + responses: + 200: + description: Success + content: + application/json;charset=utf-8: + schema: + $ref: '#/components/schemas/RawMessages' + /decode: + get: + summary: Decode raw data with the specified field defintion. + parameters: + - name: def + in: query + description: the field definition (starting with type). + allowEmptyValue: false + required: true + schema: + type: string + - name: raw + in: query + description: the raw symbols to decode as hex sequence. + required: true + allowEmptyValue: false + schema: + type: string + pattern: '^([0-9a-f][0-9a-f])+$' + responses: + 200: + description: Success + content: + application/json;charset=utf-8: + schema: + $ref: '#/components/schemas/FieldValue' /{file}: get: summary: Retrieve a particular file. @@ -391,36 +241,36 @@ paths: 500: description: General error. content: { } - head: - summary: Retrieve headers for a certain file. - parameters: - - name: file - in: path - description: the file to retrieve. - required: true - schema: - type: string - responses: - 200: - description: Success - content: - application/json;charset=utf-8: - schema: - $ref: '#/components/schemas/Data' - 400: - description: Circuit or message not found. - content: { } +# head: +# summary: Retrieve headers for a certain file. +# parameters: +# - name: file +# in: path +# description: the file to retrieve. +# required: true +# schema: +# type: string +# responses: +# 200: +# description: Success +# content: +# application/json;charset=utf-8: +# schema: +# $ref: '#/components/schemas/Data' +# 400: +# description: Circuit or message not found. +# content: { } components: schemas: Global: required: - - lastup + - version + - signal + - reconnects - masters - messages - - reconnects - - signal - - version + - lastup type: object properties: version: @@ -433,6 +283,12 @@ components: description: the result of update check ("OK" or string describing available updates). example: revision 1234abd available, 5 newer configuration files available + user: + type: string + description: logged in user name. + access: + type: string + description: access level(s) of the logged in user. signal: type: boolean description: whether signal is available. @@ -447,6 +303,26 @@ components: type: integer description: the maximum symbol rate on the bus seen since start. example: 167 + minarbitrationmicros: + minimum: 0 + type: integer + description: the minimum arbitration delay in microseconds. + example: 4231 + maxarbitrationmicros: + minimum: 0 + type: integer + description: the maximum arbitration delay in microseconds. + example: 4892 + minsymbollatency: + minimum: 0 + type: integer + description: the minimum symbol latency in milliseconds. + example: 4 + maxsymbollatency: + minimum: 0 + type: integer + description: the maximum symbol latency in milliseconds. + example: 9 qq: maximum: 255 minimum: 0 @@ -487,14 +363,15 @@ components: example: 8 messages: type: object + description: the messages with the unique key per circuit. additionalProperties: $ref: '#/components/schemas/Message' Message: required: - - lastup - name - passive - write + - lastup type: object properties: name: @@ -506,6 +383,16 @@ components: write: type: boolean description: true for a write message, false for a read message. + level: + type: string + description: the access level for the message (only with full). + pollprios: + description: the poll priority of the message (only with full). + type: integer + minimum: 0 + condition: + type: string + description: the condition string in case of a conditional message (only with full). lastup: minimum: 0 type: integer @@ -515,7 +402,7 @@ components: maximum: 255 minimum: 0 type: integer - description: limited source master address (only with def). + description: limited source master address (only with def or data). example: 49 zz: maximum: 255 @@ -535,30 +422,34 @@ components: type: string description: the message comment (only with verbose). master: - type: array + $ref: '#/components/schemas/Symbols' description: the last seen master data bytes (only with raw and if available). - items: - maximum: 255 - minimum: 0 - type: integer slave: - type: array + $ref: '#/components/schemas/Symbols' description: the last seen slave data bytes (only with raw and if available). - items: - maximum: 255 - minimum: 0 - type: integer fields: type: object additionalProperties: $ref: '#/components/schemas/Field' description: the decoded fields the message is composed of (only if available). + decodeerror: + type: string + description: set to the error message instead of fields in case of a decoding error. fielddefs: type: array description: the field definitions the message is composed of (only with def). items: $ref: '#/components/schemas/FieldDef' + Symbols: + description: master or slave data bytes. + type: array + minItems: 1 + maximum: 32 + items: + maximum: 255 + minimum: 0 + type: integer Field: type: object properties: @@ -566,7 +457,7 @@ components: type: string description: the field name. value: - type: object + $ref: '#/components/schemas/FieldValue' description: the field value. unit: type: string @@ -574,13 +465,19 @@ components: comment: type: string description: the field comment (only with verbose). + FieldValue: + description: the field value. + oneOf: + - type: string + - type: number + nullable: true FieldDef: required: - - isbits - - length - name - slave - type + - isbits + - length type: object properties: name: @@ -601,7 +498,8 @@ components: when isbits is true). divisor: type: number - description: the extra divisor applied to the raw value (only if applicable). + description: the divisor for numeric types (only if applicable, positive + for divisor, negative for reciprocal i.e. 1/-divisor). value: type: string description: the constant value (only if applicable). @@ -621,6 +519,54 @@ components: comment: type: string description: the field comment. + DataType: + description: a known field data type. + type: object + properties: + type: + type: string + description: the type name. + example: UCH + isbits: + type: boolean + description: true when the length is in bits. + isadjustable: + type: boolean + description: whether the length is adjustable. + isignored: + type: boolean + description: whether the result is ignored. + length: + type: number + minimum: -1 + maximum: 31 + description: the field length in bytes (-1 for remainder, number + of bits when isbits is true). + result: + enum: + - void + - string + - number + - date + - time + - datetime + description: the result type. + divisor: + type: number + description: the divisor for numeric types (only if applicable, positive + for divisor, negative for reciprocal i.e. 1/-divisor). + precision: + type: number + description: the precision (number of fraction digits) when divisor is >1. + required: + - type + - isbits + - length + DataTypes: + type: array + description: the known field data types. + items: + $ref: '#/components/schemas/DataType' Data: required: - global @@ -630,6 +576,38 @@ components: $ref: '#/components/schemas/Global' additionalProperties: $ref: '#/components/schemas/Circuit' + RawMessage: + type: object + description: raw message seen on the bus. + properties: + master: + $ref: '#/components/schemas/Symbols' + description: the last seen master data bytes (only with raw and if available). + slave: + $ref: '#/components/schemas/Symbols' + description: the last seen slave data bytes (only with raw and if available). + lastup: + minimum: 0 + type: integer + description: the time in UTC seconds of the last update of the message (0 + for never). + count: + type: number + description: number of times the master part was seen. + circuit: + type: string + description: name of the circuit in case of an already associated message definition. + name: + type: string + description: name of the message in case of an already associated message definition. + required: + - master + - count + RawMessages: + type: array + description: raw messages seen on the bus. + items: + $ref: '#/components/schemas/RawMessage' responses: BadRequest: description: Invalid request parameters. @@ -676,72 +654,80 @@ components: name: exact in: query description: exact search for circuit/message name. - allowEmptyValue: false + allowEmptyValue: true schema: type: boolean verboseQuery: name: verbose in: query description: include comments and field units. - allowEmptyValue: false + allowEmptyValue: true schema: type: boolean indexedQuery: name: indexed in: query description: always return field indexes instead of names. - allowEmptyValue: false + allowEmptyValue: true schema: type: boolean numericQuery: name: numeric in: query description: return numeric values of value list entries. - allowEmptyValue: false + allowEmptyValue: true schema: type: boolean valuenameQuery: name: valuename in: query description: include value and name for named values. - allowEmptyValue: false + allowEmptyValue: true schema: type: boolean fullQuery: name: full in: query description: include all available attributes. - allowEmptyValue: false + allowEmptyValue: true schema: type: boolean requiredQuery: name: required in: query description: retrieve the data from the bus if not yet cached. - allowEmptyValue: false + allowEmptyValue: true schema: type: boolean writeQuery: name: write in: query description: retrieve write messages in addition to read/poll messages. - allowEmptyValue: false + allowEmptyValue: true schema: type: boolean rawQuery: name: raw in: query description: include raw master/slave data. - allowEmptyValue: false + allowEmptyValue: true schema: type: boolean defQuery: name: def in: query description: include message and field definition. - allowEmptyValue: false + allowEmptyValue: true schema: type: boolean + defineQuery: + name: define + in: query + description: update/replace a message definition. + allowEmptyValue: false + schema: + type: string + description: message definition in CSV format. userQuery: name: user in: query @@ -756,4 +742,3 @@ components: allowEmptyValue: false schema: type: string - diff --git a/contrib/updatecheck/calcversions.sh b/contrib/updatecheck/calcversions.sh index c688342e..9893e59b 100755 --- a/contrib/updatecheck/calcversions.sh +++ b/contrib/updatecheck/calcversions.sh @@ -5,4 +5,4 @@ echo "ebusd=${version},${revision}" > versions.txt echo "ebusd=${version},${revision}" > oldversions.txt files=`find config/ -type f -or -type l` ../../src/lib/ebus/test/test_filereader $files|sed -e 's#^config/##' -e 's#^\([^ ]*\) #\1=#' -e 's# #,#g'|sort >> versions.txt -./oldtest_filereader $files|sed -e 's#^config/##' -e 's#^\([^ ]*\) #\1=#' -e 's# #,#g'|sort >> oldversions.txt +#./oldtest_filereader $files|sed -e 's#^config/##' -e 's#^\([^ ]*\) #\1=#' -e 's# #,#g'|sort >> oldversions.txt diff --git a/make_debian.sh b/make_debian.sh index 85bf0062..3e7b667c 100755 --- a/make_debian.sh +++ b/make_debian.sh @@ -15,8 +15,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -pwd -ls -la keepbuilddir= if [ "x$1" = "x--keepbuilddir" ]; then keepbuilddir=1 @@ -80,16 +78,21 @@ else fi fi -echo -echo "*************" -echo " test" -echo "*************" -echo -testdie() { - echo "test failed" - exit 1 -} -(cd src/lib/ebus/test && make test_data >/dev/null && ./test_data) || testdie +if [ -n "$RUNTEST" ]; then + echo + echo "*************" + echo " test" + echo "*************" + echo + testdie() { + echo "test failed" + exit 1 + } + ($RELEASE/usr/bin/ebusd -f -c src/lib/ebus/test -d /dev/null --checkconfig -i 10fe0900040000803e/ | egrep "received update-read broadcast test QQ=10: 0\.25$") || testdie + if [ "$RUNTEST" == "full" ]; then + (cd src/lib/ebus/test && make >/dev/null && ./test_filereader && ./test_data && ./test_message && ./test_symbol) || testdie + fi +fi echo echo "*************" @@ -97,7 +100,6 @@ echo " pack" echo "*************" echo mkdir -p $RELEASE/DEBIAN $RELEASE/etc/default $RELEASE/etc/logrotate.d || exit 1 -rm $RELEASE/usr/bin/ebusfeed mkdir -p $RELEASE/lib/systemd/system || exit 1 cp contrib/debian/systemd/ebusd.service $RELEASE/lib/systemd/system/ebusd.service || exit 1 mkdir -p $RELEASE/etc/init.d || exit 1 @@ -114,13 +116,13 @@ Architecture: $ARCH Maintainer: John Baier Homepage: https://github.com/john30/ebusd Bugs: https://github.com/john30/ebusd/issues -Depends: logrotate, libstdc++6 (>= 4.8.1), libc6, libgcc1$extralibs +Depends: libstdc++6 (>= 4.8.1), libc6, libgcc1$extralibs +Recommends: logrotate Description: eBUS daemon. ebusd is a daemon for handling communication with eBUS devices connected to a 2-wire bus system. EOF cat < $RELEASE/DEBIAN/dirs -/etc/ebusd /etc/default /etc/init.d /etc/logrotate.d diff --git a/src/ebusd/bushandler.cpp b/src/ebusd/bushandler.cpp index e2410981..0954757f 100644 --- a/src/ebusd/bushandler.cpp +++ b/src/ebusd/bushandler.cpp @@ -253,65 +253,87 @@ bool decodeType(const DataType* type, const SymbolString& input, size_t length, return !first; } -bool GrabbedMessage::dump(bool unknown, MessageMap* messages, bool first, bool decode, ostringstream* output, - bool isDirectMode) const { +bool GrabbedMessage::dump(bool unknown, MessageMap* messages, bool first, OutputFormat outputFormat, + ostringstream* output, bool isDirectMode) const { Message* message = messages->find(m_lastMaster); if (unknown && message) { return false; } if (!first) { - *output << endl; + if (outputFormat & OF_JSON) { + *output << ","; + } else { + *output << endl; + } } symbol_t dstAddress = m_lastMaster[1]; - *output << m_lastMaster.getStr(); - if (dstAddress != BROADCAST && !isMaster(dstAddress)) { - *output << (isDirectMode ? " " : " / ") << m_lastSlave.getStr(); - } - if (!isDirectMode) { - *output << " = " << m_count; + if (outputFormat & OF_JSON) { + *output << "\n{"; + if (m_lastMaster.dumpJson(false, output)) { + *output << ", "; + if (dstAddress != BROADCAST && !isMaster(dstAddress) && m_lastSlave.dumpJson(false, output)) { + *output << ", "; + } + } + *output << "\"count\": " << static_cast(m_count); + *output << ", \"lastup\": " << setw(0) << dec << m_lastTime; if (message) { - *output << ": " << message->getCircuit() << " " << message->getName(); + *output << ", \"circuit\": \"" << message->getCircuit() << "\"" + << ", \"name\": \"" << message->getName() << "\""; + } + *output << "}"; + } else { + *output << m_lastMaster.getStr(); + if (dstAddress != BROADCAST && !isMaster(dstAddress)) { + *output << (isDirectMode ? " " : " / ") << m_lastSlave.getStr(); + } + if (!isDirectMode) { + *output << " = " << m_count; + if (message) { + *output << ": " << message->getCircuit() << " " << message->getName(); + } } } - if (decode) { - DataTypeList *types = DataTypeList::getInstance(); - if (!types) { - return true; + if (!(outputFormat & OF_DEFINITION) || (outputFormat & OF_JSON)) { + return true; + } + DataTypeList *types = DataTypeList::getInstance(); + if (!types) { + return true; + } + bool master = isMaster(dstAddress) || dstAddress == BROADCAST || m_lastSlave.getDataSize() <= 0; + size_t remain = master ? m_lastMaster.getDataSize() : m_lastSlave.getDataSize(); + if (remain == 0) { + return true; + } + for (const auto& it : *types) { + const DataType* baseType = it.second; + if ((baseType->getBitCount() % 8) != 0 || baseType->isIgnored() || baseType->hasFlag(DUP)) { // skip bit and ignored types + continue; } - bool master = isMaster(dstAddress) || dstAddress == BROADCAST || m_lastSlave.getDataSize() <= 0; - size_t remain = master ? m_lastMaster.getDataSize() : m_lastSlave.getDataSize(); - if (remain == 0) { - return true; + size_t maxLength = baseType->getBitCount()/8; + bool firstOnly = maxLength >= 8; + if (maxLength > remain) { + maxLength = remain; } - for (const auto& it : *types) { - const DataType* baseType = it.second; - if ((baseType->getBitCount() % 8) != 0 || baseType->isIgnored()) { // skip bit and ignored types - continue; - } - size_t maxLength = baseType->getBitCount()/8; - bool firstOnly = maxLength >= 8; - if (maxLength > remain) { - maxLength = remain; - } - if (baseType->isAdjustableLength()) { - for (size_t length = maxLength; length >= 1; length--) { - const DataType* type = types->get(baseType->getId(), length); - bool decoded; - if (master) { - decoded = decodeType(type, m_lastMaster, length, remain-length, firstOnly, output); - } else { - decoded = decodeType(type, m_lastSlave, length, remain-length, firstOnly, output); - } - if (decoded && firstOnly) { - break; // only a single offset with maximum length when adjustable maximum size is at least 8 bytes - } - } - } else if (maxLength > 0) { + if (baseType->isAdjustableLength()) { + for (size_t length = maxLength; length >= 1; length--) { + const DataType* type = types->get(baseType->getId(), length); + bool decoded; if (master) { - decodeType(baseType, m_lastMaster, maxLength, remain-maxLength, false, output); + decoded = decodeType(type, m_lastMaster, length, remain-length, firstOnly, output); } else { - decodeType(baseType, m_lastSlave, maxLength, remain-maxLength, false, output); + decoded = decodeType(type, m_lastSlave, length, remain-length, firstOnly, output); } + if (decoded && firstOnly) { + break; // only a single offset with maximum length when adjustable maximum size is at least 8 bytes + } + } + } else if (maxLength > 0) { + if (master) { + decodeType(baseType, m_lastMaster, maxLength, remain-maxLength, false, output); + } else { + decodeType(baseType, m_lastSlave, maxLength, remain-maxLength, false, output); } } } @@ -425,6 +447,14 @@ void BusHandler::run() { } while (isRunning()); } +#ifndef FALLTHROUGH +#if defined(__GNUC__) && __GNUC__ >= 7 +#define FALLTHROUGH [[fallthrough]]; +#else +#define FALLTHROUGH +#endif +#endif + result_t BusHandler::handleSymbol() { unsigned int timeout = SYN_TIMEOUT; symbol_t sendSymbol = ESC; @@ -438,6 +468,7 @@ result_t BusHandler::handleSymbol() { case bs_skip: timeout = SYN_TIMEOUT; + FALLTHROUGH case bs_ready: if (m_currentRequest != nullptr) { setState(bs_ready, RESULT_ERR_TIMEOUT); // just to be sure an old BusRequest is cleaned up @@ -1601,10 +1632,10 @@ bool BusHandler::enableGrab(bool enable) { return true; } -void BusHandler::formatGrabResult(bool unknown, bool decode, ostringstream* output, bool isDirectMode, +void BusHandler::formatGrabResult(bool unknown, OutputFormat outputFormat, ostringstream* output, bool isDirectMode, time_t since, time_t until) const { if (!m_grabMessages) { - if (!isDirectMode) { + if (!isDirectMode && !(outputFormat & OF_JSON)) { *output << "grab disabled"; } return; @@ -1615,7 +1646,7 @@ void BusHandler::formatGrabResult(bool unknown, bool decode, ostringstream* outp || (until > 0 && it.second.getLastTime() >= until)) { continue; } - if (it.second.dump(unknown, m_messages, first, decode, output, isDirectMode)) { + if (it.second.dump(unknown, m_messages, first, outputFormat, output, isDirectMode)) { first = false; } } diff --git a/src/ebusd/bushandler.h b/src/ebusd/bushandler.h index 6c21baa8..9255108a 100755 --- a/src/ebusd/bushandler.h +++ b/src/ebusd/bushandler.h @@ -334,12 +334,12 @@ class GrabbedMessage { * @param unknown whether to dump only if this message is unknown. * @param messages the @a MessageMap instance for resolving known @a Message instances. * @param first whether this is the first message to be added to the output. - * @param decode whether to add decoding hints. + * @param outputFormat the @a OutputFormat options to use. * @param output the @a ostringstream to format the messages to. * @param isDirectMode true for direct mode, false for grab command. * @return whether the message was added to the output. */ - bool dump(bool unknown, MessageMap* messages, bool first, bool decode, ostringstream* output, + bool dump(bool unknown, MessageMap* messages, bool first, OutputFormat outputFormat, ostringstream* output, bool isDirectMode = false) const; @@ -538,13 +538,13 @@ class BusHandler : public WaitThread { /** * Format the grabbed messages to the @a ostringstream. * @param unknown whether to dump only unknown messages. - * @param decode whether to add decoding hints. + * @param outputFormat the @a OutputFormat options to use. * @param output the @a ostringstream to format the messages to. * @param isDirectMode true for direct mode, false for grab command. * @param since the start time from which to add received messages (inclusive), or 0 for all. * @param until the end time to which to add received messages (exclusive), or 0 for all. */ - void formatGrabResult(bool unknown, bool decode, ostringstream* output, bool isDirectMode = false, + void formatGrabResult(bool unknown, OutputFormat outputFormat, ostringstream* output, bool isDirectMode = false, time_t since = 0, time_t until = 0) const; /** diff --git a/src/ebusd/main.cpp b/src/ebusd/main.cpp index a708e133..9b6b3172 100644 --- a/src/ebusd/main.cpp +++ b/src/ebusd/main.cpp @@ -1388,10 +1388,10 @@ int main(int argc, char* argv[]) { s_mainLoop = new MainLoop(opt, device, s_messageMap); if (opt.injectMessages) { BusHandler* busHandler = s_mainLoop->getBusHandler(); - MasterSymbolString master; - SlaveSymbolString slave; while (arg_index < argc) { // add each passed message + MasterSymbolString master; + SlaveSymbolString slave; if (!parseMessage(argv[arg_index++], false, &master, &slave)) { continue; } diff --git a/src/ebusd/mainloop.cpp b/src/ebusd/mainloop.cpp index 6d8dab7f..c1d542c6 100644 --- a/src/ebusd/mainloop.cpp +++ b/src/ebusd/mainloop.cpp @@ -434,14 +434,14 @@ void MainLoop::run() { } if (settings.listenWithUnknown || settings.listenOnlyUnknown) { if (m_busHandler->isGrabEnabled()) { - m_busHandler->formatGrabResult(true, false, &ostream, true, since, now); + m_busHandler->formatGrabResult(true, OF_NONE, &ostream, true, since, now); } else { m_busHandler->enableGrab(true); // needed for listening to all messages } } } else if (settings.mode == cm_direct) { if (m_busHandler->isGrabEnabled()) { - m_busHandler->formatGrabResult(false, false, &ostream, true, since, now); + m_busHandler->formatGrabResult(false, OF_NONE, &ostream, true, since, now); } } // send result to client @@ -607,7 +607,7 @@ result_t MainLoop::decodeMessage(const string &data, bool isHttp, bool* connecte if (cmd == "G" || cmd == "GRAB") { return executeGrab(args, ostream); } - if (cmd == "DEFINE") { + if (cmd == "DEF" || cmd == "DEFINE") { if (m_newlyDefinedMessages) { return executeDefine(args, ostream); } @@ -921,8 +921,6 @@ result_t MainLoop::executeRead(const vector& args, const string& levels, Message* message; result_t ret; if (newDefinition) { - time_t now; - time(&now); string errorDescription; istringstream defstr("#\n" + args[argPos]); // ensure first line is not used for determining col names m_newlyDefinedMessages->clear(); @@ -1256,7 +1254,7 @@ result_t MainLoop::parseHexAndSend(const vector& args, size_t& argPos, b result_t MainLoop::executeHex(const vector& args, ostringstream* ostream) { size_t argPos = 1; result_t ret = parseHexAndSend(args, argPos, false, ostream); - if (argPos == args.size()) { + if (argPos != 0 && argPos == args.size()) { return ret; } *ostream << "usage: hex [-s QQ] ZZPBSBNN[DD]*\n" @@ -1641,7 +1639,7 @@ result_t MainLoop::executeGrab(const vector& args, ostringstream* ostrea } } if (!invalid) { - m_busHandler->formatGrabResult(onlyUnknown, decode, ostream); + m_busHandler->formatGrabResult(onlyUnknown, decode ? OF_DEFINITION : OF_NONE, ostream); return RESULT_OK; } } @@ -1677,7 +1675,7 @@ result_t MainLoop::executeDefine(const vector& args, ostringstream* ostr time(&now); string errorDescription; istringstream defstr("#\n" + args[argPos]); // ensure first line is not used for determining col names - return m_messages->readFromStream(&defstr, "temporary", now, true, nullptr, &errorDescription, replace); + return m_messages->readFromStream(&defstr, "tcp", now, true, nullptr, &errorDescription, replace); } @@ -1902,19 +1900,30 @@ result_t MainLoop::executeReload(const vector& args, ostringstream* ostr } result_t MainLoop::executeInfo(const vector& args, const string& user, ostringstream* ostream) { - if (args.size() == 0) { - *ostream << "usage: info\n" - " Report information about the daemon, the configuration, and seen devices."; + bool verbose = args.size() == 2 && args[1] == "verbose"; + if (args.size() != 1 && !verbose) { + *ostream << "usage: info [verbose]\n" + " Report information about the daemon, configuration, seen participants, and the device."; return RESULT_OK; } *ostream << "version: " << PACKAGE_STRING "." REVISION "\n"; if (!m_updateCheck.empty()) { *ostream << "update check: " << m_updateCheck << "\n"; } - string info = m_device->getEnhancedInfos(); - if (!info.empty()) { - *ostream << "device: " << info << "\n"; + *ostream << "device: " << m_device->getName(); + if (m_device->isEnhancedProto()) { + *ostream << ", enhanced"; } + if (m_device->isReadOnly()) { + *ostream << ", readonly"; + } + if (verbose) { + string info = m_device->getEnhancedInfos(); + if (!info.empty()) { + *ostream << ", " << info; + } + } + *ostream << "\n"; if (!user.empty()) { *ostream << "user: " << user << "\n"; } @@ -1962,8 +1971,8 @@ result_t MainLoop::executeHelp(ostringstream* ostream) { *ostream << "usage:\n" " read|r Read value(s): read [-f] [-m SECONDS] [-s QQ] [-d ZZ] [-c CIRCUIT] [-p PRIO] [-v|-V] [-n|-N]" " [-i VALUE[;VALUE]*] NAME [FIELD[.N]]\n" - " Read by new defintion: read [-f] [-m SECONDS] [-s QQ] [-d ZZ] [-v|-V] [-n|-N] (if enabled)" - " [-i VALUE[;VALUE]*] -def DEFINITION\n" + " Read by new defintion: read [-f] [-m SECONDS] [-s QQ] [-d ZZ] [-v|-V] [-n|-N]" + " [-i VALUE[;VALUE]*] -def DEFINITION (if enabled)\n" " Read hex message: read [-f] [-m SECONDS] [-s QQ] [-c CIRCUIT] -h ZZPBSBNN[DD]*\n" " write|w Write value(s): write [-s QQ] [-d ZZ] -c CIRCUIT NAME [VALUE[;VALUE]*]\n" " Write by new def.: write [-s QQ] [-d ZZ] -def DEFINITION [VALUE[;VALUE]*] (if enabled)\n" @@ -1975,7 +1984,7 @@ result_t MainLoop::executeHelp(ostringstream* ostream) { " listen|l Listen for updates: listen [-v|-V] [-n|-N] [-u|-U] [stop]\n" " direct Enter direct mode\n" " state|s Report bus state\n" - " info|i Report information about the daemon, the configuration, and seen devices.\n" + " info|i Report information about the daemon, configuration, seen participants, and the device.\n" " grab|g Grab messages: grab [stop]\n" " Report the messages: grab result [all]\n" " define Define new message: define [-r] DEFINITION\n" @@ -2002,9 +2011,6 @@ bool parseBoolQuery(const string& value) { } result_t MainLoop::executeGet(const vector& args, bool* connected, ostringstream* ostream) { - bool required = false, full = false, withWrite = false, raw = false; - bool withDefinition = false; - OutputFormat verbosity = OF_NAMES; time_t maxAge = -1; size_t argPos = 1; string uri = args[argPos++]; @@ -2019,6 +2025,10 @@ result_t MainLoop::executeGet(const vector& args, bool* connected, ostri circuit = uri.substr(6, pos - 6); name = uri.substr(pos + 1); } + bool required = false, full = false, withWrite = false, raw = false; + bool withDefinition = false; + string newDefinition; + OutputFormat verbosity = OF_NAMES; time_t since = 0; size_t pollPriority = 0; bool exact = false; @@ -2072,6 +2082,18 @@ result_t MainLoop::executeGet(const vector& args, bool* connected, ostri raw = parseBoolQuery(value); } else if (qname == "def") { withDefinition = parseBoolQuery(value); + } else if (qname == "define") { + if (!m_newlyDefinedMessages || circuit.empty() || name.empty() || value.empty()) { + ret = RESULT_ERR_INVALID_ARG; + break; + } + size_t comma = value.find(','); + if (comma == string::npos || comma == 0 + || value.find(circuit+","+name+",") != comma+1) { // ensure same circuit+name + ret = RESULT_ERR_INVALID_ARG; + break; + } + newDefinition = value; } else if (qname == "user") { user = value; } else if (qname == "secret") { @@ -2091,6 +2113,11 @@ result_t MainLoop::executeGet(const vector& args, bool* connected, ostri time_t now; time(&now); time_t maxLastUp = 0; + if (ret == RESULT_OK && !newDefinition.empty()) { + string errorDescription; + istringstream defstr("#\n" + newDefinition); // ensure first line is not used for determining col names + ret = m_messages->readFromStream(&defstr, "http", now, true, nullptr, &errorDescription, true); + } if (ret == RESULT_OK) { bool first = true; verbosity |= OF_JSON | (full ? OF_ALL_ATTRS : OF_NONE) | (withDefinition ? OF_DEFINITION : OF_NONE); @@ -2192,6 +2219,107 @@ result_t MainLoop::executeGet(const vector& args, bool* connected, ostri return formatHttpResult(ret, type, ostream); } // request for "/data..." + if (uri == "/datatypes") { + *ostream << "["; + OutputFormat verbosity = OF_NAMES|OF_JSON|OF_ALL_ATTRS; + DataTypeList::getInstance()->dump(verbosity, true, ostream); + *ostream << "\n]"; + type = 6; + *connected = false; + return formatHttpResult(ret, type, ostream); + } + + if (uri == "/raw") { + time_t since = 0, until = 0; + bool onlyUnknown = false; + if (args.size() > argPos) { + string query = args[argPos]; + istringstream stream(query); + string token; + while (getline(stream, token, '&')) { + size_t pos = token.find('='); + string qname, value; + if (pos != string::npos) { + qname = token.substr(0, pos); + value = token.substr(pos + 1); + } else { + qname = token; + } + if (qname == "since") { + since = parseInt(value.c_str(), 10, 0, 0xffffffff, &ret); + } else if (qname == "unknown") { + onlyUnknown = parseBoolQuery(value); + } + if (ret != RESULT_OK) { + break; + } + } + } + if (ret == RESULT_OK) { + *ostream << "["; + if (since > 0) { + time_t now; + time(&now); + until = now-1; + } + m_busHandler->formatGrabResult(onlyUnknown, OF_JSON, ostream, false, since, until); + *ostream << "\n]"; + type = 6; + } + *connected = false; + return formatHttpResult(ret, type, ostream); + } + + if (uri == "/decode") { + string def; + string raw; + if (args.size() > argPos) { + string query = args[argPos]; + istringstream stream(query); + string token; + while (getline(stream, token, '&')) { + size_t pos = token.find('='); + string qname, value; + if (pos != string::npos) { + qname = token.substr(0, pos); + value = token.substr(pos + 1); + } else { + qname = token; + } + if (qname == "def") { + def = value; + } else if (qname == "raw") { + raw = value; + } + if (ret != RESULT_OK) { + break; + } + } + } + if (ret == RESULT_OK) { + time_t now; + time(&now); + istringstream defstr("#\n" + def); // ensure first line is not used for determining col names + string errorDescription; + DataFieldTemplates* templates = getTemplates("*"); + LoadableDataFieldSet fields("", templates); + ret = fields.readFromStream(&defstr, "temporary", now, true, nullptr, &errorDescription); + if (ret == RESULT_OK) { + const SingleDataField* field = fields[0]; + SlaveSymbolString slave; + slave.push_back(0); // dummy length + ret = slave.parseHex(raw); + if (ret == RESULT_OK) { + slave.adjustHeader(); + ret = field->read(slave, 0, false, nullptr, 0, OF_JSON|OF_SHORT, 0, ostream); + } + } + type = 6; + } + *connected = false; + return formatHttpResult(ret, type, ostream); + } + if (uri.length() < 1 || uri[0] != '/' || uri.find("//") != string::npos || uri.find("..") != string::npos) { ret = RESULT_ERR_INVALID_ARG; } else { diff --git a/src/ebusd/mqtthandler.cpp b/src/ebusd/mqtthandler.cpp index d4c4b2ee..39970563 100755 --- a/src/ebusd/mqtthandler.cpp +++ b/src/ebusd/mqtthandler.cpp @@ -46,6 +46,7 @@ using std::dec; #define O_KEYF (O_CERT+1) #define O_KEPA (O_KEYF+1) #define O_INSE (O_KEPA+1) +#define O_VERB (O_INSE+1) /** the definition of the MQTT arguments. */ static const struct argp_option g_mqtt_argp_options[] = { @@ -60,6 +61,7 @@ static const struct argp_option g_mqtt_argp_options[] = { "Use MQTT TOPIC (prefix before /%circuit/%name or complete format) [ebusd]", 0 }, {"mqttretain", O_RETA, nullptr, 0, "Retain all topics instead of only selected global ones", 0 }, {"mqttjson", O_JSON, nullptr, 0, "Publish in JSON format instead of strings", 0 }, + {"mqttverbose", O_VERB, nullptr, 0, "Publish all available attributes", 0 }, #if (LIBMOSQUITTO_VERSION_NUMBER >= 1003001) {"mqttlog", O_LOGL, nullptr, 0, "Log library events", 0 }, #endif @@ -75,7 +77,7 @@ static const struct argp_option g_mqtt_argp_options[] = { {"mqttcert", O_CERT, "CERTFILE", 0, "Use CERTFILE for MQTT TLS client certificate (no default)", 0 }, {"mqttkey", O_KEYF, "KEYFILE", 0, "Use KEYFILE for MQTT TLS client certificate (no default)", 0 }, {"mqttkeypass", O_KEPA, "PASSWORD", 0, "Use PASSWORD for the encrypted KEYFILE (no default)", 0 }, - {"mqttinsecure", O_INSE, nullptr, 0, "Allow insecure TLS connection (e.g. using a self signed certificate)", 0 }, + {"mqttinsecure", O_INSE, nullptr, 0, "Allow insecure TLS connection (e.g. using a self signed certificate)", 0 }, #endif {nullptr, 0, nullptr, 0, nullptr, 0 }, @@ -189,6 +191,10 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) { g_publishFormat |= OF_JSON|OF_NAMES; break; + case O_VERB: // --mqttverbose + g_publishFormat |= OF_NAMES|OF_UNITS|OF_COMMENTS|OF_ALL_ATTRS; + break; + #if (LIBMOSQUITTO_VERSION_NUMBER >= 1003001) case O_LOGL: g_logFromLib = true; @@ -909,7 +915,7 @@ void MqttHandler::publishMessage(const Message* message, ostringstream* updates, publishTopic(getTopic(message), updates->str()); return; } - if (json) { + if (json && !(outputFormat & OF_ALL_ATTRS)) { outputFormat |= OF_SHORT; } for (size_t index = 0; index < message->getFieldCount(); index++) { diff --git a/src/lib/ebus/datatype.cpp b/src/lib/ebus/datatype.cpp index 7a3424c9..187bc129 100755 --- a/src/lib/ebus/datatype.cpp +++ b/src/lib/ebus/datatype.cpp @@ -45,7 +45,12 @@ using std::endl; bool DataType::dump(OutputFormat outputFormat, size_t length, bool appendDivisor, ostream* output) const { if (outputFormat & OF_JSON) { *output << "\"type\": \"" << m_id << "\", \"isbits\": " - << (getBitCount() < 8 ? "true" : "false") << ", \"length\": "; + << (getBitCount() < 8 ? "true" : "false"); + if (outputFormat & OF_ALL_ATTRS) { + *output << ", \"isadjustable\": " << (isAdjustableLength() ? "true" : "false"); + *output << ", \"isignored\": " << (isIgnored() ? "true" : "false"); + } + *output << ", \"length\": "; if (isAdjustableLength() && length == REMAIN_LEN) { *output << "-1"; } else { @@ -54,10 +59,11 @@ bool DataType::dump(OutputFormat outputFormat, size_t length, bool appendDivisor } else { *output << m_id; if (isAdjustableLength()) { + *output << LENGTH_SEPARATOR; if (length == REMAIN_LEN) { - *output << ":*"; + *output << "*"; } else { - *output << ":" << static_cast(length); + *output << static_cast(length); } } if (appendDivisor) { @@ -68,6 +74,14 @@ bool DataType::dump(OutputFormat outputFormat, size_t length, bool appendDivisor } +bool StringDataType::dump(OutputFormat outputFormat, size_t length, bool appendDivisor, ostream* output) const { + DataType::dump(outputFormat, length, appendDivisor, output); + if ((outputFormat & OF_JSON) && (outputFormat & OF_ALL_ATTRS)) { + *output << ", \"result\": \"" << (isIgnored() ? "void" : "string") << "\""; + } + return false; +} + result_t StringDataType::readRawValue(size_t, size_t, const SymbolString&, unsigned int*) const { return RESULT_EMPTY; } @@ -203,6 +217,14 @@ result_t StringDataType::writeSymbols(size_t offset, size_t length, istringstrea } +bool DateTimeDataType::dump(OutputFormat outputFormat, size_t length, bool appendDivisor, ostream* output) const { + DataType::dump(outputFormat, length, appendDivisor, output); + if ((outputFormat & OF_JSON) && (outputFormat & OF_ALL_ATTRS)) { + *output << ", \"result\": \"" << (hasDate() ? hasTime() ? "datetime" : "date" : "time") << "\""; + } + return false; +} + result_t DateTimeDataType::readRawValue(size_t, size_t, const SymbolString&, unsigned int*) const { return RESULT_EMPTY; } @@ -572,25 +594,32 @@ bool NumberDataType::dump(OutputFormat outputFormat, size_t length, bool appendD } else { DataType::dump(outputFormat, length, appendDivisor, output); } + if ((outputFormat & OF_JSON) && (outputFormat & OF_ALL_ATTRS)) { + *output << ", \"result\": \"number\""; + } if (!appendDivisor) { return false; } + bool ret = false; if (m_baseType) { if (m_baseType->m_divisor != m_divisor) { if (outputFormat & OF_JSON) { *output << ", \"divisor\": "; } *output << (m_divisor / m_baseType->m_divisor); - return true; + ret = true; } } else if (m_divisor != 1) { if (outputFormat & OF_JSON) { *output << ", \"divisor\": "; } *output << m_divisor; - return true; + ret = true; } - return false; + if (ret && (outputFormat & OF_JSON) && (outputFormat & OF_ALL_ATTRS)) { + *output << ", \"precision\": " << static_cast(getPrecision()); + } + return ret; } result_t NumberDataType::derive(int divisor, size_t bitCount, const NumberDataType** derived) const { @@ -985,16 +1014,18 @@ DataTypeList::DataTypeList() { // date with weekday in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99, // WW is weekday Mon=0x01 - Sun=0x07, replacement 0xff) add(new DateTimeDataType("BDA", 32, BCD, 0xff, true, false, 0)); + add(new DateTimeDataType("BDA:4", 32, BCD|DUP, 0xff, true, false, 0)); // date in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x31,0x12,0x99, replacement 0xff) - add(new DateTimeDataType("BDA", 24, BCD, 0xff, true, false, 0)); + add(new DateTimeDataType("BDA:3", 24, BCD, 0xff, true, false, 0)); // date with zero-based weekday in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,WZ,0x00 - 0x31,0x12,WZ,0x99, // WZ is zero-based weekday Mon=0x00 - Sun=0x06, replacement 0xff) add(new DateTimeDataType("BDZ", 32, BCD|SPE, 0xff, true, false, 0)); // date with weekday, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x1f,0x0c,WW,0x63, // WW is weekday Mon=0x01 - Sun=0x07, replacement 0xff) add(new DateTimeDataType("HDA", 32, 0, 0xff, true, false, 0)); + add(new DateTimeDataType("HDA:4", 32, DUP, 0xff, true, false, 0)); // date, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x1f,0x0c,0x63, replacement 0xff) - add(new DateTimeDataType("HDA", 24, 0, 0xff, true, false, 0)); + add(new DateTimeDataType("HDA:3", 24, 0, 0xff, true, false, 0)); // date, days since 01.01.1900, 01.01.1900 - 06.06.2079 (0x00,0x00 - 0xff,0xff) add(new DateTimeDataType("DAY", 16, 0, 0xff, true, false, 0)); // date+time in minutes since 01.01.2009, 01.01.2009 - 31.12.2099 (0x00,0x00,0x00,0x00 - 0x02,0xda,0x4e,0x1f) @@ -1022,13 +1053,15 @@ DataTypeList::DataTypeList() { add(new NumberDataType("BDY", 8, DAY, 0x07, 0, 6, 1)); // weekday, "Mon" - "Sun" (0x00 - 0x06) [eBUS type] add(new NumberDataType("HDY", 8, DAY, 0x00, 1, 7, 1)); // weekday, "Mon" - "Sun" (0x01 - 0x07) [Vaillant type] add(new NumberDataType("BCD", 8, BCD, 0xff, 0, 99, 1)); // unsigned decimal in BCD, 0 - 99 - add(new NumberDataType("BCD", 16, BCD, 0xffff, 0, 9999, 1)); // unsigned decimal in BCD, 0 - 9999 - add(new NumberDataType("BCD", 24, BCD, 0xffffff, 0, 999999, 1)); // unsigned decimal in BCD, 0 - 999999 - add(new NumberDataType("BCD", 32, BCD, 0xffffffff, 0, 99999999, 1)); // unsigned decimal in BCD, 0 - 99999999 + add(new NumberDataType("BCD:1", 8, BCD|DUP, 0xff, 0, 99, 1)); // unsigned decimal in BCD, 0 - 99 + add(new NumberDataType("BCD:2", 16, BCD, 0xffff, 0, 9999, 1)); // unsigned decimal in BCD, 0 - 9999 + add(new NumberDataType("BCD:3", 24, BCD, 0xffffff, 0, 999999, 1)); // unsigned decimal in BCD, 0 - 999999 + add(new NumberDataType("BCD:4", 32, BCD, 0xffffffff, 0, 99999999, 1)); // unsigned decimal in BCD, 0 - 99999999 add(new NumberDataType("HCD", 32, HCD|BCD|REQ, 0, 0, 99999999, 1)); // unsigned decimal in HCD, 0 - 99999999 - add(new NumberDataType("HCD", 8, HCD|BCD|REQ, 0, 0, 99, 1)); // unsigned decimal in HCD, 0 - 99 - add(new NumberDataType("HCD", 16, HCD|BCD|REQ, 0, 0, 9999, 1)); // unsigned decimal in HCD, 0 - 9999 - add(new NumberDataType("HCD", 24, HCD|BCD|REQ, 0, 0, 999999, 1)); // unsigned decimal in HCD, 0 - 999999 + add(new NumberDataType("HCD:4", 32, HCD|BCD|REQ|DUP, 0, 0, 99999999, 1)); // unsigned decimal in HCD, 0 - 99999999 + add(new NumberDataType("HCD:1", 8, HCD|BCD|REQ, 0, 0, 99, 1)); // unsigned decimal in HCD, 0 - 99 + add(new NumberDataType("HCD:2", 16, HCD|BCD|REQ, 0, 0, 9999, 1)); // unsigned decimal in HCD, 0 - 9999 + add(new NumberDataType("HCD:3", 24, HCD|BCD|REQ, 0, 0, 999999, 1)); // unsigned decimal in HCD, 0 - 999999 add(new NumberDataType("SCH", 8, SIG, 0x80, 0x81, 0x7f, 1)); // signed integer, -127 - +127 add(new NumberDataType("D1B", 8, SIG, 0x80, 0x81, 0x7f, 1)); // signed integer, -127 - +127 // unsigned number (fraction 1/2), 0 - 100 (0x00 - 0xc8, replacement 0xff) @@ -1076,36 +1109,48 @@ DataTypeList::DataTypeList() { add(new NumberDataType("BI4", 4, ADJ|REQ, 0, 4, 1)); // bit 4 (up to 4 bits until bit 7) add(new NumberDataType("BI5", 3, ADJ|REQ, 0, 5, 1)); // bit 5 (up to 3 bits until bit 7) add(new NumberDataType("BI6", 2, ADJ|REQ, 0, 6, 1)); // bit 6 (up to 2 bits until bit 7) - add(new NumberDataType("BI7", 1, ADJ|REQ, 0, 7, 1)); // bit 7 + add(new NumberDataType("BI7", 1, REQ, 0, 7, 1)); // bit 7 } DataTypeList* DataTypeList::getInstance() { return &s_instance; } +void DataTypeList::dump(OutputFormat outputFormat, bool appendDivisor, ostream* output) const { + bool json = outputFormat & OF_JSON; + string sep = "\n"; + for (const auto &it: m_typesById) { + const DataType *dataType = it.second; + if (dataType->hasFlag(DUP)) { + continue; + } + if (json) { + *output << sep << " {"; + } + if ((dataType->getBitCount() % 8) != 0) { + dataType->dump(outputFormat, dataType->getBitCount(), appendDivisor, output); + } else { + dataType->dump(outputFormat, dataType->getBitCount() / 8, appendDivisor, output); + } + if (json) { + *output << "}"; + sep = ",\n"; + } else { + *output << "\n"; + } + } +} + void DataTypeList::clear() { for (auto& it : m_cleanupTypes) { delete it; } m_cleanupTypes.clear(); - m_typesByIdLength.clear(); m_typesById.clear(); } result_t DataTypeList::add(const DataType* dataType) { - if (!dataType->isAdjustableLength()) { - ostringstream str; - size_t bitCount = dataType->getBitCount(); - str << dataType->getId() << LENGTH_SEPARATOR << static_cast(bitCount >= 8?bitCount/8:bitCount); - if (m_typesByIdLength.find(str.str()) != m_typesByIdLength.end()) { - return RESULT_ERR_DUPLICATE_NAME; // duplicate key - } - m_typesByIdLength[str.str()] = dataType; - if (m_typesById.find(dataType->getId()) != m_typesById.end()) { - m_cleanupTypes.push_back(dataType); - return RESULT_OK; // only store first one as default - } - } else if (m_typesById.find(dataType->getId()) != m_typesById.end()) { + if (m_typesById.find(dataType->getId()) != m_typesById.end()) { return RESULT_ERR_DUPLICATE_NAME; // duplicate key } m_typesById[dataType->getId()] = dataType; @@ -1117,8 +1162,8 @@ const DataType* DataTypeList::get(const string& id, size_t length) const { if (length > 0) { ostringstream str; str << id << LENGTH_SEPARATOR << static_cast(length); - auto it = m_typesByIdLength.find(str.str()); - if (it != m_typesByIdLength.end()) { + auto it = m_typesById.find(str.str()); + if (it != m_typesById.end()) { return it->second; } } diff --git a/src/lib/ebus/datatype.h b/src/lib/ebus/datatype.h index 825493bb..d4e76fec 100755 --- a/src/lib/ebus/datatype.h +++ b/src/lib/ebus/datatype.h @@ -178,9 +178,8 @@ enum PartType { /** bit flag for @a DataType: special marker for certain types. */ #define SPE 0x800 -/** bit flag for @a DataType: marker for a constant value. */ -#define CON 0x1000 - +/** bit flag for @a DataType: stored duplicate for backwards compatibility, not to be traversed in lists any more. */ +#define DUP 0x1000 /** * Base class for all kinds of data types. @@ -326,6 +325,9 @@ class StringDataType : public DataType { */ virtual ~StringDataType() {} + // @copydoc + bool dump(OutputFormat outputFormat, size_t length, bool appendDivisor, ostream* output) const override; + // @copydoc result_t readRawValue(size_t offset, size_t length, const SymbolString& input, unsigned int* value) const override; @@ -370,6 +372,9 @@ class DateTimeDataType : public DataType { */ virtual ~DateTimeDataType() {} + // @copydoc + bool dump(OutputFormat outputFormat, size_t length, bool appendDivisor, ostream* output) const override; + /** * @return true if date part is present. */ @@ -429,7 +434,7 @@ class NumberDataType : public DataType { NumberDataType(const string& id, size_t bitCount, uint16_t flags, unsigned int replacement, unsigned int minValue, unsigned int maxValue, int divisor, const NumberDataType* baseType = nullptr) - : DataType(id, bitCount, flags|NUM, replacement), m_minValue(minValue), m_maxValue(maxValue), m_divisor(divisor), + : DataType(id, bitCount, flags|NUM, replacement), m_minValue(minValue), m_maxValue(maxValue), m_divisor(divisor==0 ? 1 : divisor), m_precision(calcPrecision(divisor)), m_firstBit(0), m_baseType(baseType) {} /** @@ -444,7 +449,7 @@ class NumberDataType : public DataType { */ NumberDataType(const string& id, size_t bitCount, uint16_t flags, unsigned int replacement, int16_t firstBit, int divisor, const NumberDataType* baseType = nullptr) - : DataType(id, bitCount, flags|NUM, replacement), m_minValue(0), m_maxValue((1 << bitCount)-1), m_divisor(divisor), + : DataType(id, bitCount, flags|NUM, replacement), m_minValue(0), m_maxValue((1 << bitCount)-1), m_divisor(divisor==0 ? 1 : divisor), m_precision(0), m_firstBit(firstBit), m_baseType(baseType) {} /** @@ -570,6 +575,14 @@ class DataTypeList { */ static DataTypeList* getInstance(); + /** + * Dump the type list optionally including the divisor to the output. + * @param outputFormat the @a OutputFormat options. + * @param appendDivisor whether to append the divisor (if available). + * @param output the @a ostream to dump to. + */ + void dump(OutputFormat outputFormat, bool appendDivisor, ostream* output) const; + /** * Removes all @a DataType instances. */ @@ -611,12 +624,9 @@ class DataTypeList { map::const_iterator end() const { return m_typesById.end(); } private: - /** the known @a DataType instances by ID only. */ - map m_typesById; - - /** the known @a DataType instances by ID and length (i.e. "ID:BITS"). + /** the known @a DataType instances by ID (e.g. "ID:BITS" or just "ID"). * Note: adjustable length types are stored by ID only. */ - map m_typesByIdLength; + map m_typesById; /** the @a DataType instances to cleanup. */ list m_cleanupTypes; diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index 745ec084..d1464bac 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -935,20 +935,6 @@ void Message::dumpField(const string& fieldName, bool withConditions, OutputForm dumpAttribute(false, outputFormat, fieldName, output); } -void addData(const SymbolString& data, ostringstream* output) { - if (data.size() == 0) { - return; - } - *output << ",\n \"" << (data.isMaster() ? "master" : "slave") << "\": ["; - for (size_t pos = 0; pos < data.size(); pos++) { - if (pos > 0) { - *output << ", "; - } - *output << dec << static_cast(data[pos]); - } - *output << "]"; -} - void Message::decodeJson(bool leadingSeparator, bool appendDirectionCondition, bool withData, bool addRaw, OutputFormat outputFormat, ostringstream* output) const { outputFormat |= OF_JSON; @@ -1005,8 +991,8 @@ void Message::decodeJson(bool leadingSeparator, bool appendDirectionCondition, b appendAttributes(outputFormat, output); if (hasData) { if (addRaw) { - addData(m_lastMasterData, output); - addData(m_lastSlaveData, output); + m_lastMasterData.dumpJson(true, output); + m_lastSlaveData.dumpJson(true, output); *output << dec; } size_t pos = (size_t)output->tellp(); @@ -1884,27 +1870,27 @@ void MessageMap::remove(Message* message) { const auto keyIt = m_messagesByKey.find(key); bool deleted = false; if (keyIt != m_messagesByKey.end()) { - vector messages = keyIt->second; - for (auto it = messages.begin(); it != messages.end(); ) { + vector* messages = &keyIt->second; + for (auto it = messages->begin(); it != messages->end(); ) { Message* other = *it; if (other == message) { if (!deleted) { deleted = true; delete(other); } - messages.erase(it); + it = messages->erase(it); } else { ++it; } } - if (messages.empty()) { + if (messages->empty()) { m_messagesByKey.erase(keyIt); } } bool storedByName = false; for (auto nameIt = m_messagesByName.begin(); nameIt != m_messagesByName.end(); ) { - vector messages = nameIt->second; - for (auto it = messages.begin(); it != messages.end(); ) { + vector* messages = &nameIt->second; + for (auto it = messages->begin(); it != messages->end(); ) { Message* other = *it; if (other == message) { storedByName = true; @@ -1912,13 +1898,13 @@ void MessageMap::remove(Message* message) { deleted = true; delete(other); } - messages.erase(it); + it = messages->erase(it); } else { ++it; } } - if (messages.empty()) { - m_messagesByName.erase(nameIt); + if (messages->empty()) { + nameIt = m_messagesByName.erase(nameIt); } else { ++nameIt; } diff --git a/src/lib/ebus/message.h b/src/lib/ebus/message.h index f9a3bdd7..16d34c30 100644 --- a/src/lib/ebus/message.h +++ b/src/lib/ebus/message.h @@ -122,7 +122,11 @@ class Message : public AttributedItem { /** * Destructor. */ - virtual ~Message() { if (m_deleteData) { delete m_data; } } + virtual ~Message() { + if (m_deleteData) { + delete m_data; + } + } /** * Calculate the key for the ID. diff --git a/src/lib/ebus/symbol.cpp b/src/lib/ebus/symbol.cpp index c6e91612..b97ea1da 100755 --- a/src/lib/ebus/symbol.cpp +++ b/src/lib/ebus/symbol.cpp @@ -28,6 +28,7 @@ namespace ebusd { using std::ostringstream; using std::nouppercase; using std::setw; +using std::dec; using std::hex; using std::setfill; @@ -157,6 +158,24 @@ const string SymbolString::getStr(size_t skipFirstSymbols) const { return sstr.str(); } +bool SymbolString::dumpJson(bool withSeparator, ostringstream* output) const { + if (size() == 0) { + return false; + } + if (withSeparator) { + *output << ",\n "; + } + *output << "\"" << (isMaster() ? "master" : "slave") << "\": ["; + for (size_t pos = 0; pos < size(); pos++) { + if (pos > 0) { + *output << ", "; + } + *output << dec << static_cast(m_data[pos]); + } + *output << "]"; + return true; +} + symbol_t SymbolString::calcCrc() const { symbol_t crc = 0; for (size_t i = 0; i < m_data.size(); i++) { diff --git a/src/lib/ebus/symbol.h b/src/lib/ebus/symbol.h index c3aef275..e69f6844 100755 --- a/src/lib/ebus/symbol.h +++ b/src/lib/ebus/symbol.h @@ -67,6 +67,7 @@ namespace ebusd { using std::string; using std::vector; +using std::ostringstream; /** the base type for symbols sent to/from the eBUS. */ typedef unsigned char symbol_t; @@ -158,6 +159,14 @@ class SymbolString { */ const string getStr(size_t skipFirstSymbols = 0) const; + /** + * Dump the data in JSON format to the output. + * @param withSeparator true to prepend the field separator. + * @param output the @a ostringstream to format the messages to. + * @return true if something was written to the output. + */ + bool dumpJson(bool withSeparator, ostringstream* output) const; + /** * Return a reference to the symbol at the specified index. * @param index the index of the symbol to return. diff --git a/src/lib/ebus/test/test.csv b/src/lib/ebus/test/test.csv new file mode 100644 index 00000000..b23e3e6c --- /dev/null +++ b/src/lib/ebus/test/test.csv @@ -0,0 +1,2 @@ +# +b,broadcast,test,,,fe,0900,,,,EXP diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp index 0f9a94a5..2b1bf798 100644 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -154,22 +154,22 @@ int main() { {"w,ehp,multi,,,,,01:8;02:2;03,longname,,STR:15", "ABCDEFGHIJKLMNO", "ff08b5090a0e014142434445464748;ff08b509040e02494a;ff08b509070e034b4c4d4e4f", "00;00;00", "dC" }, {"w,ehp,multi,,,,,01:8;02:2;0304,longname,,STR:15", "ABCDEFGHIJKLMNO", "ff08b5090a0e014142434445464748;ff08b509040e02494a;ff08b509070e034b4c4d4e4f", "00;00;00", "cC" }, {"r,ehp,scan,chained scan,,08,B509,24:9;25;26;27,,,IGN,,,,id4,,STR:28", "21074500100027790000000000N8", "ff08b5090124;ff08b5090125;ff08b5090126;ff08b5090127", "09003231303734353030;09313030303237373930;09303030303030303030;024E38", "dC" }, - {"r,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7:1,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B71;B61", "ff08b509030d6900", "03138040", "d" }, - {"r,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7:1,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B71;B60", "ff08b509030d6900", "0313ffbf", "d" }, - {"r,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7:1,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B70;B61", "ff08b509030d6900", "03137fff", "d" }, - {"r,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7:1,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B70;B60", "ff08b509030d6900", "03137fbf", "d" }, - {"r,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7:1,0=B70;1=B71", "1.9;B61;B71", "ff08b509030d6a00", "0213ff", "d" }, - {"r,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7:1,0=B70;1=B71", "1.9;B60;B71", "ff08b509030d6a00", "0213bf", "d" }, - {"r,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7:1,0=B70;1=B71", "1.9;B61;B70", "ff08b509030d6a00", "02137f", "d" }, - {"r,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7:1,0=B70;1=B71", "1.9;B60;B70", "ff08b509030d6a00", "02133f", "d" }, - {"w,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7:1,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B71;B61", "ff08b509060e6900138040", "00", "di" }, - {"w,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7:1,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B71;B60", "ff08b509060e6900138000", "00", "di" }, - {"w,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7:1,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B70;B61", "ff08b509060e6900130040", "00", "di" }, - {"w,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7:1,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B70;B60", "ff08b509060e6900130000", "00", "di" }, - {"w,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7:1,0=B70;1=B71", "1.9;B61;B71", "ff08b509050e6a0013c0", "00", "di" }, - {"w,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7:1,0=B70;1=B71", "1.9;B60;B71", "ff08b509050e6a001380", "00", "di" }, - {"w,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7:1,0=B70;1=B71", "1.9;B61;B70", "ff08b509050e6a001340", "00", "di" }, - {"w,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7:1,0=B70;1=B71", "1.9;B60;B70", "ff08b509050e6a001300", "00", "di" }, + {"r,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B71;B61", "ff08b509030d6900", "03138040", "d" }, + {"r,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B71;B60", "ff08b509030d6900", "0313ffbf", "d" }, + {"r,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B70;B61", "ff08b509030d6900", "03137fff", "d" }, + {"r,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B70;B60", "ff08b509030d6900", "03137fbf", "d" }, + {"r,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7,0=B70;1=B71", "1.9;B61;B71", "ff08b509030d6a00", "0213ff", "d" }, + {"r,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7,0=B70;1=B71", "1.9;B60;B71", "ff08b509030d6a00", "0213bf", "d" }, + {"r,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7,0=B70;1=B71", "1.9;B61;B70", "ff08b509030d6a00", "02137f", "d" }, + {"r,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7,0=B70;1=B71", "1.9;B60;B70", "ff08b509030d6a00", "02133f", "d" }, + {"w,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B71;B61", "ff08b509060e6900138040", "00", "di" }, + {"w,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B71;B60", "ff08b509060e6900138000", "00", "di" }, + {"w,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B70;B61", "ff08b509060e6900130040", "00", "di" }, + {"w,,x,,,,,6900,,,UCH,10,bar,,Bit7,,BI7,0=B70;1=B71,,,Bit6,,BI6:1,0=B60;1=B61", "1.9;B70;B60", "ff08b509060e6900130000", "00", "di" }, + {"w,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7,0=B70;1=B71", "1.9;B61;B71", "ff08b509050e6a0013c0", "00", "di" }, + {"w,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7,0=B70;1=B71", "1.9;B60;B71", "ff08b509050e6a001380", "00", "di" }, + {"w,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7,0=B70;1=B71", "1.9;B61;B70", "ff08b509050e6a001340", "00", "di" }, + {"w,,x,,,,,6a00,,,UCH,10,bar,,Bit6,,BI6:1,0=B60;1=B61,,,Bit7,,BI7,0=B70;1=B71", "1.9;B60;B70", "ff08b509050e6a001300", "00", "di" }, {"w,,x,,,,,,,,IGN:1,,,,b0,,BI0:1,,,,b1,,BI1:1,,,,b2,,BI2:1,,,,,,IGN:1,,,,c0,,BI0:1,,,,c1,,BI1:1,,,,c2,,BI2:1", "1;1;1;0;0;0", "ff08b509050e00070000", "00", "di" }, {"w,,x,,,,,,,,IGN:1,,,,b0,,BI0:1,,,,b1,,BI1:1,,,,b2,,BI2:1,,,,,,IGN:1,,,,c0,,BI0:1,,,,c1,,BI1:1,,,,c2,,BI2:1", "1;0;0;0;0;1", "ff08b509050e00010004", "00", "di" }, {"w,,x,,,,,,,,IGN:1,,,,b0,,BI0:1,,,,b1,,BI1:1,,,,b2,,BI2:1,,,,,,IGN:1,,,,c0,,BI0:1,,,,c1,,BI1:1,,,,c2,,BI2:1", "0;0;1;0;1;1", "ff08b509050e00040006", "00", "di" }, diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 27f5f0a4..f24b1f2b 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -1,20 +1,13 @@ set(ebusctl_SOURCES ebusctl.cpp) -set(ebusfeed_SOURCES ebusfeed.cpp) set(ebuspicloader_SOURCES ebuspicloader.cpp intelhex/intelhexclass.cpp) -if(HAVE_CONTRIB) - set(ebusfeed_LIBS ${ebusfeed_LIBS} ebuscontrib) -endif(HAVE_CONTRIB) - include_directories(../lib/ebus) include_directories(../lib/utils) include_directories(intelhex) add_executable(ebusctl ${ebusctl_SOURCES}) -add_executable(ebusfeed ${ebusfeed_SOURCES}) add_executable(ebuspicloader ${ebuspicloader_SOURCES}) target_link_libraries(ebusctl utils ebus ${LIB_ARGP} ${ebusctl_LIBS}) -target_link_libraries(ebusfeed ebus ${LIB_ARGP} ${ebusfeed_LIBS}) target_link_libraries(ebuspicloader ${LIB_ARGP}) install(TARGETS ebusctl ebuspicloader EXPORT ebusd DESTINATION usr/bin) diff --git a/src/tools/Makefile.am b/src/tools/Makefile.am index cd095d2a..49d31551 100644 --- a/src/tools/Makefile.am +++ b/src/tools/Makefile.am @@ -2,22 +2,13 @@ AM_CXXFLAGS = -I$(top_srcdir)/src \ -isystem$(top_srcdir) bin_PROGRAMS = ebusctl \ - ebusfeed \ ebuspicloader ebusctl_SOURCES = ebusctl.cpp ebusctl_LDADD = ../lib/utils/libutils.a -ebusfeed_SOURCES = ebusfeed.cpp -ebusfeed_LDADD = ../lib/utils/libutils.a \ - ../lib/ebus/libebus.a - ebuspicloader_SOURCES = ebuspicloader.cpp intelhex/intelhexclass.cpp -if CONTRIB -ebusfeed_LDADD += ../lib/ebus/contrib/libebuscontrib.a -endif - distclean-local: -rm -f Makefile.in -rm -rf .libs diff --git a/test_coverage.sh b/test_coverage.sh index 74a13521..8f25bc19 100755 --- a/test_coverage.sh +++ b/test_coverage.sh @@ -63,15 +63,6 @@ EOF ./src/ebusd/ebusd -c contrib/etc/ebusd --checkconfig >/dev/null rm -f contrib/etc/ebusd/bad.csv echo > dump -./src/tools/ebusfeed -d tcp:127.0.0.1:8876 -t 10000 dump >/dev/null 2>/dev/null -./src/tools/ebusfeed -d tcp:127.0.0.1:99999 dump >/dev/null 2>/dev/null -./src/tools/ebusfeed -d udp:127.0.0.1:8876 -t 10000 dump >/dev/null 2>/dev/null -./src/tools/ebusfeed -d udp:127.0.0.1:8876 -t 10000 nonexistdump >/dev/null 2>/dev/null -./src/tools/ebusfeed -d "" >/dev/null 2>/dev/null -./src/tools/ebusfeed -t 1 >/dev/null 2>/dev/null -./src/tools/ebusfeed "" >/dev/null 2>/dev/null -./src/tools/ebusfeed 1 2 >/dev/null 2>/dev/null -./src/tools/ebusfeed -x >/dev/null 2>/dev/null ./src/tools/ebusctl -s testserver -p 100000 >/dev/null 2>/dev/null ./src/tools/ebusctl -s "" >/dev/null 2>/dev/null ./src/tools/ebusctl -p "" >/dev/null 2>/dev/null