From 5b09b06bcffc39ffd8ae5d88cf0cf12a56178a0f Mon Sep 17 00:00:00 2001 From: Tijmen van Nesselrooij Date: Sat, 25 Jun 2022 22:17:46 +0200 Subject: [PATCH] Rewrite electricity-logger to use an sqlite3 database --- .clang-format | 107 + .gitignore | 2 + .vscode/c_cpp_properties.json | 19 + .vscode/configurationCache.log | 1 + .vscode/dryrun.log | 55 + .vscode/extensions.json | 5 + .vscode/settings.json | 79 + .vscode/targets.log | 829 +++++++ LICENSE | 2 +- README.md | 51 +- bin/electricity-logger | Bin 0 -> 580088 bytes compile_flags.txt | 6 + docs/BENCHMARK.md | 75 + docs/ELECTRICITY_API.md | 37 + docs/ELECTRICITY_LOGGER.md | 24 + docs/SERVER.md | 43 + docs/SOLAR_API.md | 42 + docs/SOLAR_LOGGER.md | 22 + include/cxxopts.hpp | 2086 +++++++++++++++++ include/electricity/logger/database.hpp | 15 + include/electricity/logger/dsmr.hpp | 73 + include/electricity/logger/serialport.hpp | 24 + include/electricity/server/api.hpp | 10 + include/electricity/server/configuration.hpp | 33 + include/electricity/server/database.hpp | 8 + include/migrator/migrations.hpp | 9 + include/migrator/transaction.hpp | 24 + include/solar/logger/database.hpp | 25 + include/solar/logger/zeverdata.hpp | 33 + include/solar/server/api.hpp | 10 + include/solar/server/configuration.hpp | 18 + include/solar/server/database/connection.hpp | 30 + include/solar/server/database/database.hpp | 20 + include/util/date.hpp | 151 ++ makefile | 109 + script/electricity/createdb.sh | 32 + script/electricity/test.db | Bin 0 -> 16384 bytes script/solar/README.md | 12 + script/solar/createdb.sh | 30 + script/solar/migratedb.sh | 41 + src/electricity-logger/database.cpp | 60 + src/electricity-logger/dsmr.cpp | 174 ++ src/electricity-logger/main.cpp | 117 + src/electricity-logger/serialport.cpp | 55 + src/electricity-server/main.cpp | 51 + src/electricity-server/server/api.cpp | 96 + .../server/configuration.cpp | 98 + src/electricity-server/server/database.cpp | 211 ++ src/migrator/main.cpp | 32 + src/migrator/migrations/epochtodatetime.cpp | 91 + .../migrations/updatesummarytable.cpp | 68 + src/migrator/transaction.cpp | 35 + src/solar-logger/database.cpp | 53 + src/solar-logger/main.cpp | 60 + src/solar-logger/zeverdata.cpp | 88 + src/solar-server/api.cpp | 93 + src/solar-server/configuration.cpp | 24 + src/solar-server/database/connection.cpp | 241 ++ src/solar-server/database/database.cpp | 33 + src/solar-server/main.cpp | 42 + systemd/electricity-server.service | 13 + systemd/solar-server.service | 13 + 62 files changed, 5937 insertions(+), 3 deletions(-) create mode 100644 .clang-format create mode 100644 .vscode/c_cpp_properties.json create mode 100644 .vscode/configurationCache.log create mode 100644 .vscode/dryrun.log create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/targets.log create mode 100755 bin/electricity-logger create mode 100644 compile_flags.txt create mode 100644 docs/BENCHMARK.md create mode 100644 docs/ELECTRICITY_API.md create mode 100644 docs/ELECTRICITY_LOGGER.md create mode 100644 docs/SERVER.md create mode 100644 docs/SOLAR_API.md create mode 100644 docs/SOLAR_LOGGER.md create mode 100644 include/cxxopts.hpp create mode 100644 include/electricity/logger/database.hpp create mode 100644 include/electricity/logger/dsmr.hpp create mode 100644 include/electricity/logger/serialport.hpp create mode 100644 include/electricity/server/api.hpp create mode 100644 include/electricity/server/configuration.hpp create mode 100644 include/electricity/server/database.hpp create mode 100644 include/migrator/migrations.hpp create mode 100644 include/migrator/transaction.hpp create mode 100644 include/solar/logger/database.hpp create mode 100644 include/solar/logger/zeverdata.hpp create mode 100644 include/solar/server/api.hpp create mode 100644 include/solar/server/configuration.hpp create mode 100644 include/solar/server/database/connection.hpp create mode 100644 include/solar/server/database/database.hpp create mode 100644 include/util/date.hpp create mode 100644 makefile create mode 100755 script/electricity/createdb.sh create mode 100644 script/electricity/test.db create mode 100644 script/solar/README.md create mode 100755 script/solar/createdb.sh create mode 100755 script/solar/migratedb.sh create mode 100644 src/electricity-logger/database.cpp create mode 100644 src/electricity-logger/dsmr.cpp create mode 100644 src/electricity-logger/main.cpp create mode 100644 src/electricity-logger/serialport.cpp create mode 100644 src/electricity-server/main.cpp create mode 100644 src/electricity-server/server/api.cpp create mode 100644 src/electricity-server/server/configuration.cpp create mode 100644 src/electricity-server/server/database.cpp create mode 100644 src/migrator/main.cpp create mode 100644 src/migrator/migrations/epochtodatetime.cpp create mode 100644 src/migrator/migrations/updatesummarytable.cpp create mode 100644 src/migrator/transaction.cpp create mode 100644 src/solar-logger/database.cpp create mode 100644 src/solar-logger/main.cpp create mode 100644 src/solar-logger/zeverdata.cpp create mode 100644 src/solar-server/api.cpp create mode 100644 src/solar-server/configuration.cpp create mode 100644 src/solar-server/database/connection.cpp create mode 100644 src/solar-server/database/database.cpp create mode 100644 src/solar-server/main.cpp create mode 100644 systemd/electricity-server.service create mode 100644 systemd/solar-server.service diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..64b5d4d --- /dev/null +++ b/.clang-format @@ -0,0 +1,107 @@ +--- +Language: Cpp + +DisableFormat: false +Standard: Latest +BasedOnStyle: WebKit +TabWidth: 4 +IndentWidth: 4 +ContinuationIndentWidth: 4 +ConstructorInitializerIndentWidth: 1 +UseTab: Never +ColumnLimit: 120 + +AccessModifierOffset: -4 +AlignAfterOpenBracket: AlwaysBreak +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignConsecutiveMacros: false +AlignEscapedNewlines: DontAlign +AlignOperands: false +AlignTrailingComments: false +AllowAllArgumentsOnNextLine: false +AllowAllConstructorInitializersOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortLambdasOnASingleLine: Inline +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: No +BinPackArguments: false +BinPackParameters: false + +# Configure each individual brace in BraceWrapping +BreakBeforeBraces: Custom +# Control of individual brace wrapping cases +BraceWrapping: + AfterCaseLabel: true + AfterClass: false + AfterControlStatement: Always + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: true + BeforeElse: true + BeforeLambdaBody: true + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: true + +BreakAfterJavaFieldAnnotations: true +BreakBeforeTernaryOperators: false +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +BreakStringLiterals: false +CommentPragmas: "^ IWYU pragma:" +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +Cpp11BracedListStyle: true +FixNamespaceComments: false +IndentCaseLabels: true +IndentPPDirectives: BeforeHash +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: "" +MacroBlockEnd: "" +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: All +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 + +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Middle +# QualifierAlignment: Right # Only supported in clang-format 14+ +# ReferenceAlignmentStyle: Middle # Only supported in clang-format 14+ +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: true +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: Never +SpaceBeforeRangeBasedForLoopColon: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: false +SpacesInParentheses: false +SpacesInSquareBrackets: false + +# Comments are for developers, they should arrange them +ReflowComments: false + +IncludeBlocks: Preserve +--- diff --git a/.gitignore b/.gitignore index e257658..c248bb8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +build/ + # ---> C++ # Prerequisites *.d diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..5624bd8 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,19 @@ +{ + "configurations": [ + { + "name": "Linux", + "intelliSenseMode": "gcc-x64", + "includePath": [ + "${workspaceFolder}/include" + ], + "defines": [ + "SPDLOG_FMT_EXTERNAL" + ], + "forcedInclude": [], + "compilerPath": "/usr/bin/gcc", + "cStandard": "c11", + "cppStandard": "c++17" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/configurationCache.log b/.vscode/configurationCache.log new file mode 100644 index 0000000..df53f4b --- /dev/null +++ b/.vscode/configurationCache.log @@ -0,0 +1 @@ +{"buildTargets":["all","bin/electricity-logger","bin/electricity-server","bin/migrator","bin/solar-logger","bin/solar-server","build/electricity-logger/database.o","build/electricity-logger/dsmr.o","build/electricity-logger/main.o","build/electricity-logger/serialport.o","build/solar-logger/main.o","check-electricity-logger","check-electricity-server","check-solar-logger","check-solar-server","clean","install","install-electricity-server","install-loggers","install-servers","install-solar-server","solarpaneloutput.db"],"launchTargets":["/home/tijmen/project/home-data-collection-tools/bin>electricity-logger()","/home/tijmen/project/home-data-collection-tools/bin>electricity-server()","/home/tijmen/project/home-data-collection-tools/bin>migrator()","/home/tijmen/project/home-data-collection-tools/bin>solar-logger()","/home/tijmen/project/home-data-collection-tools/bin>solar-server()"],"customConfigurationProvider":{"workspaceBrowse":{"browsePath":["/home/tijmen/project/home-data-collection-tools/include/","/home/tijmen/project/home-data-collection-tools/src/electricity-logger","/home/tijmen/project/home-data-collection-tools/src/electricity-server","/home/tijmen/project/home-data-collection-tools/src/electricity-server/server","/home/tijmen/project/home-data-collection-tools/src/migrator","/home/tijmen/project/home-data-collection-tools/src/migrator/migrations","/home/tijmen/project/home-data-collection-tools/src/solar-logger","/home/tijmen/project/home-data-collection-tools/src/solar-server","/home/tijmen/project/home-data-collection-tools/src/solar-server/database"],"compilerArgs":["-Wall","-Wextra","-O2","-MMD","-c","src/electricity-server/server/database.cpp","-o","build/electricity-server/server/database.o"],"compilerPath":"/usr/bin/g++","standard":"c++20","windowsSdkVersion":""},"fileIndex":[["/home/tijmen/project/home-data-collection-tools/src/solar-logger/main.cpp",{"uri":{"$mid":1,"fsPath":"/home/tijmen/project/home-data-collection-tools/src/solar-logger/main.cpp","path":"/home/tijmen/project/home-data-collection-tools/src/solar-logger/main.cpp","scheme":"file"},"configuration":{"defines":["SPDLOG_FMT_EXTERNAL"],"standard":"c++20","includePath":["/home/tijmen/project/home-data-collection-tools/include/"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/g++","compilerArgs":["-Wall","-Wextra","-O2","-MMD","-c","src/solar-logger/main.cpp","-o","build/solar-logger/main.o"],"windowsSdkVersion":""},"compileCommand":{"command":"g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/solar-logger/main.cpp -o build/solar-logger/main.o","directory":"/home/tijmen/project/home-data-collection-tools","file":"/home/tijmen/project/home-data-collection-tools/src/solar-logger/main.cpp"}}],["/home/tijmen/project/home-data-collection-tools/src/solar-logger/zeverdata.cpp",{"uri":{"$mid":1,"fsPath":"/home/tijmen/project/home-data-collection-tools/src/solar-logger/zeverdata.cpp","path":"/home/tijmen/project/home-data-collection-tools/src/solar-logger/zeverdata.cpp","scheme":"file"},"configuration":{"defines":["SPDLOG_FMT_EXTERNAL"],"standard":"c++20","includePath":["/home/tijmen/project/home-data-collection-tools/include/"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/g++","compilerArgs":["-Wall","-Wextra","-O2","-MMD","-c","src/solar-logger/zeverdata.cpp","-o","build/solar-logger/zeverdata.o"],"windowsSdkVersion":""},"compileCommand":{"command":"g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/solar-logger/zeverdata.cpp -o build/solar-logger/zeverdata.o","directory":"/home/tijmen/project/home-data-collection-tools","file":"/home/tijmen/project/home-data-collection-tools/src/solar-logger/zeverdata.cpp"}}],["/home/tijmen/project/home-data-collection-tools/src/solar-logger/database.cpp",{"uri":{"$mid":1,"fsPath":"/home/tijmen/project/home-data-collection-tools/src/solar-logger/database.cpp","path":"/home/tijmen/project/home-data-collection-tools/src/solar-logger/database.cpp","scheme":"file"},"configuration":{"defines":["SPDLOG_FMT_EXTERNAL"],"standard":"c++20","includePath":["/home/tijmen/project/home-data-collection-tools/include/"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/g++","compilerArgs":["-Wall","-Wextra","-O2","-MMD","-c","src/solar-logger/database.cpp","-o","build/solar-logger/database.o"],"windowsSdkVersion":""},"compileCommand":{"command":"g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/solar-logger/database.cpp -o build/solar-logger/database.o","directory":"/home/tijmen/project/home-data-collection-tools","file":"/home/tijmen/project/home-data-collection-tools/src/solar-logger/database.cpp"}}],["/home/tijmen/project/home-data-collection-tools/src/solar-server/database/connection.cpp",{"uri":{"$mid":1,"fsPath":"/home/tijmen/project/home-data-collection-tools/src/solar-server/database/connection.cpp","path":"/home/tijmen/project/home-data-collection-tools/src/solar-server/database/connection.cpp","scheme":"file"},"configuration":{"defines":["SPDLOG_FMT_EXTERNAL"],"standard":"c++20","includePath":["/home/tijmen/project/home-data-collection-tools/include/"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/g++","compilerArgs":["-Wall","-Wextra","-O2","-MMD","-c","src/solar-server/database/connection.cpp","-o","build/solar-server/database/connection.o"],"windowsSdkVersion":""},"compileCommand":{"command":"g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/solar-server/database/connection.cpp -o build/solar-server/database/connection.o","directory":"/home/tijmen/project/home-data-collection-tools","file":"/home/tijmen/project/home-data-collection-tools/src/solar-server/database/connection.cpp"}}],["/home/tijmen/project/home-data-collection-tools/src/solar-server/database/database.cpp",{"uri":{"$mid":1,"fsPath":"/home/tijmen/project/home-data-collection-tools/src/solar-server/database/database.cpp","path":"/home/tijmen/project/home-data-collection-tools/src/solar-server/database/database.cpp","scheme":"file"},"configuration":{"defines":["SPDLOG_FMT_EXTERNAL"],"standard":"c++20","includePath":["/home/tijmen/project/home-data-collection-tools/include/"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/g++","compilerArgs":["-Wall","-Wextra","-O2","-MMD","-c","src/solar-server/database/database.cpp","-o","build/solar-server/database/database.o"],"windowsSdkVersion":""},"compileCommand":{"command":"g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/solar-server/database/database.cpp -o build/solar-server/database/database.o","directory":"/home/tijmen/project/home-data-collection-tools","file":"/home/tijmen/project/home-data-collection-tools/src/solar-server/database/database.cpp"}}],["/home/tijmen/project/home-data-collection-tools/src/solar-server/api.cpp",{"uri":{"$mid":1,"fsPath":"/home/tijmen/project/home-data-collection-tools/src/solar-server/api.cpp","path":"/home/tijmen/project/home-data-collection-tools/src/solar-server/api.cpp","scheme":"file"},"configuration":{"defines":["SPDLOG_FMT_EXTERNAL"],"standard":"c++20","includePath":["/home/tijmen/project/home-data-collection-tools/include/"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/g++","compilerArgs":["-Wall","-Wextra","-O2","-MMD","-c","src/solar-server/api.cpp","-o","build/solar-server/api.o"],"windowsSdkVersion":""},"compileCommand":{"command":"g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/solar-server/api.cpp -o build/solar-server/api.o","directory":"/home/tijmen/project/home-data-collection-tools","file":"/home/tijmen/project/home-data-collection-tools/src/solar-server/api.cpp"}}],["/home/tijmen/project/home-data-collection-tools/src/solar-server/main.cpp",{"uri":{"$mid":1,"fsPath":"/home/tijmen/project/home-data-collection-tools/src/solar-server/main.cpp","path":"/home/tijmen/project/home-data-collection-tools/src/solar-server/main.cpp","scheme":"file"},"configuration":{"defines":["SPDLOG_FMT_EXTERNAL"],"standard":"c++20","includePath":["/home/tijmen/project/home-data-collection-tools/include/"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/g++","compilerArgs":["-Wall","-Wextra","-O2","-MMD","-c","src/solar-server/main.cpp","-o","build/solar-server/main.o"],"windowsSdkVersion":""},"compileCommand":{"command":"g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/solar-server/main.cpp -o build/solar-server/main.o","directory":"/home/tijmen/project/home-data-collection-tools","file":"/home/tijmen/project/home-data-collection-tools/src/solar-server/main.cpp"}}],["/home/tijmen/project/home-data-collection-tools/src/solar-server/configuration.cpp",{"uri":{"$mid":1,"fsPath":"/home/tijmen/project/home-data-collection-tools/src/solar-server/configuration.cpp","path":"/home/tijmen/project/home-data-collection-tools/src/solar-server/configuration.cpp","scheme":"file"},"configuration":{"defines":["SPDLOG_FMT_EXTERNAL"],"standard":"c++20","includePath":["/home/tijmen/project/home-data-collection-tools/include/"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/g++","compilerArgs":["-Wall","-Wextra","-O2","-MMD","-c","src/solar-server/configuration.cpp","-o","build/solar-server/configuration.o"],"windowsSdkVersion":""},"compileCommand":{"command":"g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/solar-server/configuration.cpp -o build/solar-server/configuration.o","directory":"/home/tijmen/project/home-data-collection-tools","file":"/home/tijmen/project/home-data-collection-tools/src/solar-server/configuration.cpp"}}],["/home/tijmen/project/home-data-collection-tools/src/migrator/migrations/updatesummarytable.cpp",{"uri":{"$mid":1,"fsPath":"/home/tijmen/project/home-data-collection-tools/src/migrator/migrations/updatesummarytable.cpp","path":"/home/tijmen/project/home-data-collection-tools/src/migrator/migrations/updatesummarytable.cpp","scheme":"file"},"configuration":{"defines":["SPDLOG_FMT_EXTERNAL"],"standard":"c++20","includePath":["/home/tijmen/project/home-data-collection-tools/include/"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/g++","compilerArgs":["-Wall","-Wextra","-O2","-MMD","-c","src/migrator/migrations/updatesummarytable.cpp","-o","build/migrator/migrations/updatesummarytable.o"],"windowsSdkVersion":""},"compileCommand":{"command":"g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/migrator/migrations/updatesummarytable.cpp -o build/migrator/migrations/updatesummarytable.o","directory":"/home/tijmen/project/home-data-collection-tools","file":"/home/tijmen/project/home-data-collection-tools/src/migrator/migrations/updatesummarytable.cpp"}}],["/home/tijmen/project/home-data-collection-tools/src/migrator/migrations/epochtodatetime.cpp",{"uri":{"$mid":1,"fsPath":"/home/tijmen/project/home-data-collection-tools/src/migrator/migrations/epochtodatetime.cpp","path":"/home/tijmen/project/home-data-collection-tools/src/migrator/migrations/epochtodatetime.cpp","scheme":"file"},"configuration":{"defines":["SPDLOG_FMT_EXTERNAL"],"standard":"c++20","includePath":["/home/tijmen/project/home-data-collection-tools/include/"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/g++","compilerArgs":["-Wall","-Wextra","-O2","-MMD","-c","src/migrator/migrations/epochtodatetime.cpp","-o","build/migrator/migrations/epochtodatetime.o"],"windowsSdkVersion":""},"compileCommand":{"command":"g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/migrator/migrations/epochtodatetime.cpp -o build/migrator/migrations/epochtodatetime.o","directory":"/home/tijmen/project/home-data-collection-tools","file":"/home/tijmen/project/home-data-collection-tools/src/migrator/migrations/epochtodatetime.cpp"}}],["/home/tijmen/project/home-data-collection-tools/src/migrator/main.cpp",{"uri":{"$mid":1,"fsPath":"/home/tijmen/project/home-data-collection-tools/src/migrator/main.cpp","path":"/home/tijmen/project/home-data-collection-tools/src/migrator/main.cpp","scheme":"file"},"configuration":{"defines":["SPDLOG_FMT_EXTERNAL"],"standard":"c++20","includePath":["/home/tijmen/project/home-data-collection-tools/include/"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/g++","compilerArgs":["-Wall","-Wextra","-O2","-MMD","-c","src/migrator/main.cpp","-o","build/migrator/main.o"],"windowsSdkVersion":""},"compileCommand":{"command":"g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/migrator/main.cpp -o build/migrator/main.o","directory":"/home/tijmen/project/home-data-collection-tools","file":"/home/tijmen/project/home-data-collection-tools/src/migrator/main.cpp"}}],["/home/tijmen/project/home-data-collection-tools/src/migrator/transaction.cpp",{"uri":{"$mid":1,"fsPath":"/home/tijmen/project/home-data-collection-tools/src/migrator/transaction.cpp","path":"/home/tijmen/project/home-data-collection-tools/src/migrator/transaction.cpp","scheme":"file"},"configuration":{"defines":["SPDLOG_FMT_EXTERNAL"],"standard":"c++20","includePath":["/home/tijmen/project/home-data-collection-tools/include/"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/g++","compilerArgs":["-Wall","-Wextra","-O2","-MMD","-c","src/migrator/transaction.cpp","-o","build/migrator/transaction.o"],"windowsSdkVersion":""},"compileCommand":{"command":"g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/migrator/transaction.cpp -o build/migrator/transaction.o","directory":"/home/tijmen/project/home-data-collection-tools","file":"/home/tijmen/project/home-data-collection-tools/src/migrator/transaction.cpp"}}],["/home/tijmen/project/home-data-collection-tools/src/electricity-logger/serialport.cpp",{"uri":{"$mid":1,"fsPath":"/home/tijmen/project/home-data-collection-tools/src/electricity-logger/serialport.cpp","path":"/home/tijmen/project/home-data-collection-tools/src/electricity-logger/serialport.cpp","scheme":"file"},"configuration":{"defines":["SPDLOG_FMT_EXTERNAL"],"standard":"c++20","includePath":["/home/tijmen/project/home-data-collection-tools/include/"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/g++","compilerArgs":["-Wall","-Wextra","-O2","-MMD","-c","src/electricity-logger/serialport.cpp","-o","build/electricity-logger/serialport.o"],"windowsSdkVersion":""},"compileCommand":{"command":"g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/electricity-logger/serialport.cpp -o build/electricity-logger/serialport.o","directory":"/home/tijmen/project/home-data-collection-tools","file":"/home/tijmen/project/home-data-collection-tools/src/electricity-logger/serialport.cpp"}}],["/home/tijmen/project/home-data-collection-tools/src/electricity-logger/dsmr.cpp",{"uri":{"$mid":1,"fsPath":"/home/tijmen/project/home-data-collection-tools/src/electricity-logger/dsmr.cpp","path":"/home/tijmen/project/home-data-collection-tools/src/electricity-logger/dsmr.cpp","scheme":"file"},"configuration":{"defines":["SPDLOG_FMT_EXTERNAL"],"standard":"c++20","includePath":["/home/tijmen/project/home-data-collection-tools/include/"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/g++","compilerArgs":["-Wall","-Wextra","-O2","-MMD","-c","src/electricity-logger/dsmr.cpp","-o","build/electricity-logger/dsmr.o"],"windowsSdkVersion":""},"compileCommand":{"command":"g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/electricity-logger/dsmr.cpp -o build/electricity-logger/dsmr.o","directory":"/home/tijmen/project/home-data-collection-tools","file":"/home/tijmen/project/home-data-collection-tools/src/electricity-logger/dsmr.cpp"}}],["/home/tijmen/project/home-data-collection-tools/src/electricity-logger/main.cpp",{"uri":{"$mid":1,"fsPath":"/home/tijmen/project/home-data-collection-tools/src/electricity-logger/main.cpp","path":"/home/tijmen/project/home-data-collection-tools/src/electricity-logger/main.cpp","scheme":"file"},"configuration":{"defines":["SPDLOG_FMT_EXTERNAL"],"standard":"c++20","includePath":["/home/tijmen/project/home-data-collection-tools/include/"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/g++","compilerArgs":["-Wall","-Wextra","-O2","-MMD","-c","src/electricity-logger/main.cpp","-o","build/electricity-logger/main.o"],"windowsSdkVersion":""},"compileCommand":{"command":"g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/electricity-logger/main.cpp -o build/electricity-logger/main.o","directory":"/home/tijmen/project/home-data-collection-tools","file":"/home/tijmen/project/home-data-collection-tools/src/electricity-logger/main.cpp"}}],["/home/tijmen/project/home-data-collection-tools/src/electricity-logger/database.cpp",{"uri":{"$mid":1,"fsPath":"/home/tijmen/project/home-data-collection-tools/src/electricity-logger/database.cpp","path":"/home/tijmen/project/home-data-collection-tools/src/electricity-logger/database.cpp","scheme":"file"},"configuration":{"defines":["SPDLOG_FMT_EXTERNAL"],"standard":"c++20","includePath":["/home/tijmen/project/home-data-collection-tools/include/"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/g++","compilerArgs":["-Wall","-Wextra","-O2","-MMD","-c","src/electricity-logger/database.cpp","-o","build/electricity-logger/database.o"],"windowsSdkVersion":""},"compileCommand":{"command":"g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/electricity-logger/database.cpp -o build/electricity-logger/database.o","directory":"/home/tijmen/project/home-data-collection-tools","file":"/home/tijmen/project/home-data-collection-tools/src/electricity-logger/database.cpp"}}],["/home/tijmen/project/home-data-collection-tools/src/electricity-server/main.cpp",{"uri":{"$mid":1,"fsPath":"/home/tijmen/project/home-data-collection-tools/src/electricity-server/main.cpp","path":"/home/tijmen/project/home-data-collection-tools/src/electricity-server/main.cpp","scheme":"file"},"configuration":{"defines":["SPDLOG_FMT_EXTERNAL"],"standard":"c++20","includePath":["/home/tijmen/project/home-data-collection-tools/include/"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/g++","compilerArgs":["-Wall","-Wextra","-O2","-MMD","-c","src/electricity-server/main.cpp","-o","build/electricity-server/main.o"],"windowsSdkVersion":""},"compileCommand":{"command":"g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/electricity-server/main.cpp -o build/electricity-server/main.o","directory":"/home/tijmen/project/home-data-collection-tools","file":"/home/tijmen/project/home-data-collection-tools/src/electricity-server/main.cpp"}}],["/home/tijmen/project/home-data-collection-tools/src/electricity-server/server/api.cpp",{"uri":{"$mid":1,"fsPath":"/home/tijmen/project/home-data-collection-tools/src/electricity-server/server/api.cpp","path":"/home/tijmen/project/home-data-collection-tools/src/electricity-server/server/api.cpp","scheme":"file"},"configuration":{"defines":["SPDLOG_FMT_EXTERNAL"],"standard":"c++20","includePath":["/home/tijmen/project/home-data-collection-tools/include/"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/g++","compilerArgs":["-Wall","-Wextra","-O2","-MMD","-c","src/electricity-server/server/api.cpp","-o","build/electricity-server/server/api.o"],"windowsSdkVersion":""},"compileCommand":{"command":"g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/electricity-server/server/api.cpp -o build/electricity-server/server/api.o","directory":"/home/tijmen/project/home-data-collection-tools","file":"/home/tijmen/project/home-data-collection-tools/src/electricity-server/server/api.cpp"}}],["/home/tijmen/project/home-data-collection-tools/src/electricity-server/server/configuration.cpp",{"uri":{"$mid":1,"fsPath":"/home/tijmen/project/home-data-collection-tools/src/electricity-server/server/configuration.cpp","path":"/home/tijmen/project/home-data-collection-tools/src/electricity-server/server/configuration.cpp","scheme":"file"},"configuration":{"defines":["SPDLOG_FMT_EXTERNAL"],"standard":"c++20","includePath":["/home/tijmen/project/home-data-collection-tools/include/"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/g++","compilerArgs":["-Wall","-Wextra","-O2","-MMD","-c","src/electricity-server/server/configuration.cpp","-o","build/electricity-server/server/configuration.o"],"windowsSdkVersion":""},"compileCommand":{"command":"g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/electricity-server/server/configuration.cpp -o build/electricity-server/server/configuration.o","directory":"/home/tijmen/project/home-data-collection-tools","file":"/home/tijmen/project/home-data-collection-tools/src/electricity-server/server/configuration.cpp"}}],["/home/tijmen/project/home-data-collection-tools/src/electricity-server/server/database.cpp",{"uri":{"$mid":1,"fsPath":"/home/tijmen/project/home-data-collection-tools/src/electricity-server/server/database.cpp","path":"/home/tijmen/project/home-data-collection-tools/src/electricity-server/server/database.cpp","scheme":"file"},"configuration":{"defines":["SPDLOG_FMT_EXTERNAL"],"standard":"c++20","includePath":["/home/tijmen/project/home-data-collection-tools/include/"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/g++","compilerArgs":["-Wall","-Wextra","-O2","-MMD","-c","src/electricity-server/server/database.cpp","-o","build/electricity-server/server/database.o"],"windowsSdkVersion":""},"compileCommand":{"command":"g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/electricity-server/server/database.cpp -o build/electricity-server/server/database.o","directory":"/home/tijmen/project/home-data-collection-tools","file":"/home/tijmen/project/home-data-collection-tools/src/electricity-server/server/database.cpp"}}]]}} \ No newline at end of file diff --git a/.vscode/dryrun.log b/.vscode/dryrun.log new file mode 100644 index 0000000..01f1fcf --- /dev/null +++ b/.vscode/dryrun.log @@ -0,0 +1,55 @@ +make --dry-run --always-make --keep-going --print-directory +make: Entering directory '/home/tijmen/project/home-data-collection-tools' + +mkdir -p build/solar-logger +g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/solar-logger/main.cpp -o build/solar-logger/main.o +mkdir -p build/solar-logger +g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/solar-logger/zeverdata.cpp -o build/solar-logger/zeverdata.o +mkdir -p build/solar-logger +g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/solar-logger/database.cpp -o build/solar-logger/database.o +mkdir -p bin +g++ build/solar-logger/main.o build/solar-logger/zeverdata.o build/solar-logger/database.o -lsqlite3 -lcurl -o bin/solar-logger +mkdir -p build/solar-server/database +g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/solar-server/database/connection.cpp -o build/solar-server/database/connection.o +mkdir -p build/solar-server/database +g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/solar-server/database/database.cpp -o build/solar-server/database/database.o +mkdir -p build/solar-server +g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/solar-server/api.cpp -o build/solar-server/api.o +mkdir -p build/solar-server +g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/solar-server/main.cpp -o build/solar-server/main.o +mkdir -p build/solar-server +g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/solar-server/configuration.cpp -o build/solar-server/configuration.o +mkdir -p bin +g++ build/solar-server/database/connection.o build/solar-server/database/database.o build/solar-server/api.o build/solar-server/main.o build/solar-server/configuration.o -lpistache -lsqlite3 -lstdc++fs -lspdlog -lfmt -o bin/solar-server +mkdir -p build/migrator/migrations +g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/migrator/migrations/updatesummarytable.cpp -o build/migrator/migrations/updatesummarytable.o +mkdir -p build/migrator/migrations +g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/migrator/migrations/epochtodatetime.cpp -o build/migrator/migrations/epochtodatetime.o +mkdir -p build/migrator +g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/migrator/main.cpp -o build/migrator/main.o +mkdir -p build/migrator +g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/migrator/transaction.cpp -o build/migrator/transaction.o +mkdir -p bin +g++ build/migrator/migrations/updatesummarytable.o build/migrator/migrations/epochtodatetime.o build/migrator/main.o build/migrator/transaction.o -lsqlite3 -o bin/migrator +mkdir -p build/electricity-logger +g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/electricity-logger/serialport.cpp -o build/electricity-logger/serialport.o +mkdir -p build/electricity-logger +g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/electricity-logger/dsmr.cpp -o build/electricity-logger/dsmr.o +mkdir -p build/electricity-logger +g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/electricity-logger/main.cpp -o build/electricity-logger/main.o +mkdir -p build/electricity-logger +g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/electricity-logger/database.cpp -o build/electricity-logger/database.o +mkdir -p bin +g++ build/electricity-logger/serialport.o build/electricity-logger/dsmr.o build/electricity-logger/main.o build/electricity-logger/database.o -lsqlite3 -lspdlog -lfmt -o bin/electricity-logger +mkdir -p build/electricity-server +g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/electricity-server/main.cpp -o build/electricity-server/main.o +mkdir -p build/electricity-server/server +g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/electricity-server/server/api.cpp -o build/electricity-server/server/api.o +mkdir -p build/electricity-server/server +g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/electricity-server/server/configuration.cpp -o build/electricity-server/server/configuration.o +mkdir -p build/electricity-server/server +g++ -DSPDLOG_FMT_EXTERNAL -Wall -Wextra -std=c++20 -O2 -Iinclude/ -MMD -c src/electricity-server/server/database.cpp -o build/electricity-server/server/database.o +mkdir -p bin +g++ build/electricity-server/main.o build/electricity-server/server/api.o build/electricity-server/server/configuration.o build/electricity-server/server/database.o -lpistache -lsqlite3 -lstdc++fs -lspdlog -lfmt -o bin/electricity-server +make: Leaving directory '/home/tijmen/project/home-data-collection-tools' + diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..e977881 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "llvm-vs-code-extensions.vscode-clangd", + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..989aab9 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,79 @@ +{ + "editor.detectIndentation": true, + "editor.insertSpaces": true, + "editor.tabSize": 4, + "files.associations": { + "string": "cpp", + "array": "cpp", + "atomic": "cpp", + "hash_map": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "bitset": "cpp", + "cctype": "cpp", + "chrono": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "concepts": "cpp", + "condition_variable": "cpp", + "csignal": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "forward_list": "cpp", + "list": "cpp", + "map": "cpp", + "set": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "ratio": "cpp", + "regex": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "future": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "mutex": "cpp", + "new": "cpp", + "numbers": "cpp", + "ostream": "cpp", + "semaphore": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "thread": "cpp", + "cinttypes": "cpp", + "typeindex": "cpp", + "typeinfo": "cpp", + "valarray": "cpp", + "variant": "cpp", + "strstream": "cpp" + } +} \ No newline at end of file diff --git a/.vscode/targets.log b/.vscode/targets.log new file mode 100644 index 0000000..6ac0569 --- /dev/null +++ b/.vscode/targets.log @@ -0,0 +1,829 @@ +make all --print-data-base --no-builtin-variables --no-builtin-rules --question +# GNU Make 4.3 +# Built for x86_64-pc-linux-gnu +# Copyright (C) 1988-2020 Free Software Foundation, Inc. +# License GPLv3+: GNU GPL version 3 or later +# This is free software: you are free to change and redistribute it. +# There is NO WARRANTY, to the extent permitted by law. + +# Make data base, printed on Mon Jun 27 19:09:36 2022 + +# Variables + +# environment +GDK_BACKEND = x11 +# environment +LC_ALL = C +# environment +NO_AT_BRIDGE = 1 +# environment +GTK_RC_FILES = /etc/gtk/gtkrc:/home/tijmen/.gtkrc:/home/tijmen/.config/gtkrc +# makefile (from 'makefile', line 16) +MIGRATOR_CPPS = $(shell find src/migrator/ -name *.cpp) +# makefile (from 'makefile', line 30) +MIGRATOR_BINARY_PATH = bin/migrator +# makefile (from 'makefile', line 9) +SOLAR_LOGGER_OBJS = $(patsubst src/%.cpp, build/%.o, ${SOLAR_LOGGER_CPPS}) +# environment +VSCODE_IPC_HOOK_EXTHOST = /run/user/1000/vscode-ipc-582970dc-f3ab-44e6-8729-662e27dd760f.sock +# environment +KONSOLE_DBUS_SERVICE = :1.81 + +# environment +LC_NUMERIC = en_US.UTF-8 +# environment +VSCODE_CWD = /home/tijmen/project/home-data-collection-tools +# environment +WINDOWID = 115343367 +# environment +WINDOWPATH = 1 +# makefile (from 'makefile', line 17) +MIGRATOR_OBJS = $(patsubst src/%.cpp, build/%.o, ${MIGRATOR_CPPS}) +# default +MAKE_COMMAND := make +# automatic +@D = $(patsubst %/,%,$(dir $@)) +# makefile (from 'makefile', line 31) +ELECT_LOGGER_BINARY_PATH = bin/electricity-logger +# environment +KONSOLE_VERSION = 220402 +# environment +VSCODE_HANDLES_UNCAUGHT_ERRORS = true +# default +.VARIABLES := +# environment +PWD = /home/tijmen/project/home-data-collection-tools +# automatic +%D = $(patsubst %/,%,$(dir $%)) +# environment +MAIL = /var/spool/mail/tijmen +# makefile (from 'makefile', line 24) +ELECT_SRV_CPPS = $(shell find src/electricity-server/ -name *.cpp) +# environment +OLDPWD = /home/tijmen +# environment +KONSOLE_DBUS_WINDOW = /Windows/1 +# automatic +^D = $(patsubst %/,%,$(dir $^)) +# makefile (from 'makefile', line 25) +ELECT_SRV_OBJS = $(patsubst src/%.cpp, build/%.o, ${ELECT_SRV_CPPS}) +# environment +VSCODE_LOG_STACK = false +# automatic +%F = $(notdir $%) +# makefile (from 'makefile', line 5) +SERVER_LFLAGS = -lpistache -lsqlite3 -lstdc++fs -lspdlog -lfmt +# environment +VSCODE_CODE_CACHE_PATH = /home/tijmen/.config/Code/CachedData/30d9c6cd9483b2cc586687151bcbcd635f373630 +# environment +LANG = C +# environment +XAUTHORITY = /home/tijmen/.Xauthority +# default +.LOADED := +# default +.INCLUDE_DIRS = /usr/include /usr/local/include /usr/include +# environment +COLORFGBG = 15;0 +# makefile +MAKEFLAGS = pqrR +# makefile +CURDIR := /home/tijmen/project/home-data-collection-tools +# environment +VSCODE_PIPE_LOGGING = true +# environment +APPLICATION_INSIGHTS_NO_DIAGNOSTIC_CHANNEL = 1 +# automatic +*D = $(patsubst %/,%,$(dir $*)) +# environment +MFLAGS = -pqrR +# default +.SHELLFLAGS := -c +# makefile (from 'makefile', line 3) +ELECTRICITY_LOGGER_LFLAGS = -lsqlite3 -lspdlog -lfmt +# makefile (from 'makefile', line 29) +SOLAR_SRV_BINARY_PATH = bin/solar-server +# environment +XDG_CONFIG_DIRS = /home/tijmen/.config/kdedefaults:/etc/xdg +# automatic ++D = $(patsubst %/,%,$(dir $+)) +# environment +XCURSOR_THEME = breeze_cursors +# makefile (from 'build/electricity-logger/database.d', line 1) +MAKEFILE_LIST := makefile build/electricity-logger/serialport.d build/electricity-logger/dsmr.d build/electricity-logger/main.d build/electricity-logger/database.d +# automatic +@F = $(notdir $@) +# environment +VSCODE_VERBOSE_LOGGING = true +# environment +VSCODE_PID = 2616 +# environment +XDG_SESSION_TYPE = tty +# automatic +?D = $(patsubst %/,%,$(dir $?)) +# environment +SESSION_MANAGER = local/ARCHDESKTOP:@/tmp/.ICE-unix/942,unix/ARCHDESKTOP:/tmp/.ICE-unix/942 +# automatic +*F = $(notdir $*) +# environment +CHROME_DESKTOP = code-url-handler.desktop +# environment +DBUS_SESSION_BUS_ADDRESS = unix:path=/run/user/1000/bus +# automatic + +Copyright (c) 2022 Tijmen van Nesselrooij Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/README.md b/README.md index 487f61c..3d3b50c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,50 @@ -# home-data-collection-tools +# Home Data Collection Tools -A collection of tools to log collected data from a Zeverlution smart inverter and DSMR protocol supporting meters. \ No newline at end of file +A mono repository containing all the homebrew collectors and REST APIs running on the local server. See it in action [here](https://valkendaal.duckdns.org). + +## Contents + +This repository houses various projects. All are listed below. + +- The Zeverlution S3000 logger, [documentation](docs/SOLAR_LOGGER.md) +- The Landis Gyr E350 logger, [documentation](docs/ELECTRICITY_LOGGER.md) +- Two pistache REST HTTP APIs, [documentation](docs/SERVER.md) + - A solar panel log server, [documentation](docs/SOLAR_API.md) + - An electricity log server, [documentation](docs/ELECTRICITY_API.md) +- A migrator to convert and build data structures yielded by the loggers, [documentation](docs/MIGRATOR.md) + +## Project Directory + +|- `.vscode` => A folder with Visual Studio Code IDE specific files, for developing this project
+|- `docs` => A folder housing all the documentation files (`*.md`)
+|- `include` => A folder housing all the header files used by the source files in `src/`
+|- `script` => A folder with handy bash scripts to create and migrate databases
+|- `src` => A folder with all the source files of the different projects that require compilation
+|....|- `electricity-logger` => The Landis Gyr E350 logger source files
+|....|- `electricity-server` => The pistache REST API sources for serving the electricity logs
+|....|- `migrator ` => The migrator source files
+|....|- `solar-logger` => The Zeverlution S3000 logger source files
+|....|- `solar-server` => The pistache REST API sources for serving the solar panel logs
+|- `systemd` => A folder with example systemd service files for the servers
+ +## Miscellaneous + +A few benchmarks have been done for the solar-server project, which can be found [here](docs/BENCHMARK.md). + +## Dependencies + +### Runtime (server) + +- Curl: the multiprotocol file tranfser library, [website](https://curl.haxx.se/libcurl/) +- cxxopts, [website](https://github.com/jarro2783/cxxopts/tree/v3.0.0) +- Docker CE, [website](https://www.docker.com/) +- GNU Make, [website](https://www.gnu.org/software/make/) +- Pistache: an elegant C++ REST framework, [website](http://pistache.io/) +- Spdlog, [website](https://github.com/gabime/spdlog) +- Sqlite3: a small SQL database engine, [website](https://www.sqlite.org/index.html) + +### Development + +In addition to all the runtime dependencies the following dependencies are required for development: + +- A C++20 compatible compiler diff --git a/bin/electricity-logger b/bin/electricity-logger new file mode 100755 index 0000000000000000000000000000000000000000..01e0c7fe47ff5d2d5ff4b2e5a90711a5713c7e72 GIT binary patch literal 580088 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ɫDr{Nz~!L^T+CSN&}^WXmBpjTz4l(u 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଼l9JxXl0YLTb^)0tK;iQwZUdC?|8 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�k3RcM6GN+J;kpy>V`o!zTIq>NG`N9H&E2P({2Wn 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 "$outputFile" +``` + +Use the `--help` switch for more information about the possible arguments `electricity-logger` can take. \ No newline at end of file diff --git a/docs/SERVER.md b/docs/SERVER.md new file mode 100644 index 0000000..b376c84 --- /dev/null +++ b/docs/SERVER.md @@ -0,0 +1,43 @@ +# Serving Data + +This project includes to data servers: the solar server and electricity server. Both host the data collected by their respective logger counterparts. + +## API Description + +[The solar api description](./SOLAR_API.md) +[The electricity api description](./ELECTRICITY_API.md) + +## Reverse Proxy + +It is recommended to use a reverse proxy setup to make all servers and content reachable through standard HTTP(S) ports. When using nginx something like this suffices, using the solar server as example: +``` +server { + server_name solar.valkendaal.duckdns.org; + location / { + if ($request_method = 'GET') { + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Methods' 'GET'; + } + proxy_pass http://localhost:3001; + } +} +``` + +The additional if statement within the location scope allows fetching of solar resources by any other domain. This is used to display data exposed by the solar server on the website (`public/`). + +## Restricting Access + +The electricity server exposes sensitive data, hence it shouldn't be accessible to anyone except users of the household. The easy solution here is to verify the requestee's IP address, since anyone making the request from the household itself should share the same external IP address, including the server. Therefore the electricity server checks the requestee's IP address against its own external one (by resolving the given domain parameter argument to an IP address). + +For this a little hackery was necessary in the reverse proxy, since it normally makes the request to the electricity server on its own behalf. This would result in all requests originating from 127.0.0.1 (localhost). To solve this the following line was added before the `proxy_pass` directive: +``` +proxy_set_header X-Real-IP $remote_addr; +``` + +The value of the X-Real-IP HTTP header is then used by the electricity server to validate against the domain resolved IP address. If they match it means the request came from the same network as the server. + +This obviously is not watertight, but it serves the purpose well enough and avoids having to lay down more complicated authorization infrastructure. + +## Launch Parameters + +Both servers use TCLAP for their launch parameters. Simply run either executable without any parameters or use the `--help` switch to get all available commands. \ No newline at end of file diff --git a/docs/SOLAR_API.md b/docs/SOLAR_API.md new file mode 100644 index 0000000..304616e --- /dev/null +++ b/docs/SOLAR_API.md @@ -0,0 +1,42 @@ +# The solar-server REST API + +This project depends on the `pistache` HTTP framework, see their [website](http://pistache.io/) for more info. + +## Endpoints +All endpoints respond in JSON. Examples can be found in the Examples section. Dates are always in ISO format, meaning they take the shape of `year-month-day` with leading zeroes for month and day. Example: `2019-01-11` is the eleventh day of January, 2019. + +- `/day?start=[yyyy-MM-dd]` This tells the server what date to serve all the collected records from the specified day. +- `/day?start=[yyyy-MM-dd]&stop=[yyyy-MM-dd]` This tells the server what date to serve the highest recorded kilowatt hour collected for each day in the specified date range. Stop date is inclusive. +- `/month?&start=[yyyy-mm]&stop=[yyyy-mm]` This returns the total kilowatthours generated for a given month. The stop month is inclusive. + +## Example Response +All times are always in UTC. For these examples the current date is 25 December, 2019. + +### /day?start=2019-02-15 +Will give you as many objects as there are recorded values for the 15th of Febuary, 2019. Ordered from earliest to latest. +```json +[ + { + "time": 1550226776, + "watt": 1456, + "kwh": 14.53 + }, + { + "time": 1550226834, + "watt": 1456, + "kwh": 14.54 + }, + ... +] +``` + +### /month?start=2019-06&stop=2019-06 +Will give you a total kilowatt hours generated for the month July, 2019. The time component is the first day of the month at 00:00 (midnight) UTC. For multiple months the result is ordered earliest to latest. +```json +[ + { + "time": 1559347200, + "watt": 0, + "kwh": 451.64 + } +] \ No newline at end of file diff --git a/docs/SOLAR_LOGGER.md b/docs/SOLAR_LOGGER.md new file mode 100644 index 0000000..c6b3ccf --- /dev/null +++ b/docs/SOLAR_LOGGER.md @@ -0,0 +1,22 @@ +# About +This software targets linux and has been tested on both x86_64 and armv7 hardware. + +## solar-logger +Simple data collecting program for ZeverSolar's Zeverlution Sxxxx "smart" inverters with a network interface (referred to as "combox" by the manufacturer). It collects all the exposed data of the Zeverlution, including current power generation (watts) and today's cummulative power production (kilowatt/hours). + +### Strange output +Zeverlution Smart Inverters currently have a bug that causes leading zeroes in a decimal number to be ignored. Concretely this means that the value 0.01 becomes 0.10, 3.09 becomes 3.9, etcetera. This is causing strange peaks in the logged data where sequences go from 2.80 to 2.90 to 2.10. + +Another bug is the inverter turning itself off and back on again throughout the day. This happens if the yield get too low. This will cause the cumulative power to reset to zero (kilowatt per hour). + +# Building +## Dependencies +### solar-logger +Dependencies for this program are: +- `libcurl` which can be installed using your package manager. It has been tested with the `openSSL` flavour, libcurl version 4. +- `sqlite3` which is sometimes also referred to as `libsqlite3-dev`. + +## Building +The logger program can be build by running the makefile (`make all`) in the project root. It will create a `bin` folder where it puts the newly created binaries. Move these to wherever you keep your binaries or use the `install` make target. + +Refer to the `--help` switch to find out more about supported launch parameters. diff --git a/include/cxxopts.hpp b/include/cxxopts.hpp new file mode 100644 index 0000000..4855966 --- /dev/null +++ b/include/cxxopts.hpp @@ -0,0 +1,2086 @@ +/* + +Copyright (c) 2014, 2015, 2016, 2017 Jarryd Beck + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef CXXOPTS_HPP_INCLUDED +#define CXXOPTS_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__GNUC__) && !defined(__clang__) + #if(__GNUC__ * 10 + __GNUC_MINOR__) < 49 + #define CXXOPTS_NO_REGEX true + #endif +#endif + +#ifndef CXXOPTS_NO_REGEX + #include +#endif // CXXOPTS_NO_REGEX + +// Nonstandard before C++17, which is coincidentally what we also need for +#ifdef __has_include + #if __has_include() + #include + #ifdef __cpp_lib_optional + #define CXXOPTS_HAS_OPTIONAL + #endif + #endif +#endif + +#if __cplusplus >= 201603L + #define CXXOPTS_NODISCARD [[nodiscard]] +#else + #define CXXOPTS_NODISCARD +#endif + +#ifndef CXXOPTS_VECTOR_DELIMITER + #define CXXOPTS_VECTOR_DELIMITER ',' +#endif + +#define CXXOPTS__VERSION_MAJOR 3 +#define CXXOPTS__VERSION_MINOR 0 +#define CXXOPTS__VERSION_PATCH 0 + +#if(__GNUC__ < 10 || (__GNUC__ == 10 && __GNUC_MINOR__ < 1)) && __GNUC__ >= 6 + #define CXXOPTS_NULL_DEREF_IGNORE +#endif + +namespace cxxopts +{ + static constexpr struct + { + uint8_t major, minor, patch; + } version = {CXXOPTS__VERSION_MAJOR, CXXOPTS__VERSION_MINOR, CXXOPTS__VERSION_PATCH}; +} // namespace cxxopts + +//when we ask cxxopts to use Unicode, help strings are processed using ICU, +//which results in the correct lengths being computed for strings when they +//are formatted for the help output +//it is necessary to make sure that can be found by the +//compiler, and that icu-uc is linked in to the binary. + +#ifdef CXXOPTS_USE_UNICODE + #include + +namespace cxxopts +{ + using String = icu::UnicodeString; + + inline String toLocalString(std::string s) { return icu::UnicodeString::fromUTF8(std::move(s)); } + + #if defined(__GNUC__) + // GNU GCC with -Weffc++ will issue a warning regarding the upcoming class, we want to silence it: + // warning: base class 'class std::enable_shared_from_this' has accessible non-virtual destructor + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" + #pragma GCC diagnostic ignored "-Weffc++" + // This will be ignored under other compilers like LLVM clang. + #endif + class UnicodeStringIterator : public std::iterator { + public: + UnicodeStringIterator(const icu::UnicodeString * string, int32_t pos) : s(string), i(pos) { } + + value_type operator*() const { return s->char32At(i); } + + bool operator==(const UnicodeStringIterator & rhs) const { return s == rhs.s && i == rhs.i; } + + bool operator!=(const UnicodeStringIterator & rhs) const { return !(*this == rhs); } + + UnicodeStringIterator & operator++() + { + ++i; + return *this; + } + + UnicodeStringIterator operator+(int32_t v) { return UnicodeStringIterator(s, i + v); } + + private: + const icu::UnicodeString * s; + int32_t i; + }; + #if defined(__GNUC__) + #pragma GCC diagnostic pop + #endif + + inline String & stringAppend(String & s, String a) { return s.append(std::move(a)); } + + inline String & stringAppend(String & s, size_t n, UChar32 c) + { + for(size_t i = 0; i != n; ++i) + { + s.append(c); + } + + return s; + } + + template String & stringAppend(String & s, Iterator begin, Iterator end) + { + while(begin != end) + { + s.append(*begin); + ++begin; + } + + return s; + } + + inline size_t stringLength(const String & s) { return s.length(); } + + inline std::string toUTF8String(const String & s) + { + std::string result; + s.toUTF8String(result); + + return result; + } + + inline bool empty(const String & s) { return s.isEmpty(); } +} + +namespace std +{ + inline cxxopts::UnicodeStringIterator begin(const icu::UnicodeString & s) + { + return cxxopts::UnicodeStringIterator(&s, 0); + } + + inline cxxopts::UnicodeStringIterator end(const icu::UnicodeString & s) + { + return cxxopts::UnicodeStringIterator(&s, s.length()); + } +} + +//ifdef CXXOPTS_USE_UNICODE +#else + +namespace cxxopts +{ + using String = std::string; + + template T toLocalString(T && t) { return std::forward(t); } + + inline size_t stringLength(const String & s) { return s.length(); } + + inline String & stringAppend(String & s, const String & a) { return s.append(a); } + + inline String & stringAppend(String & s, size_t n, char c) { return s.append(n, c); } + + template String & stringAppend(String & s, Iterator begin, Iterator end) + { + return s.append(begin, end); + } + + template std::string toUTF8String(T && t) { return std::forward(t); } + + inline bool empty(const std::string & s) { return s.empty(); } +} // namespace cxxopts + +//ifdef CXXOPTS_USE_UNICODE +#endif + +namespace cxxopts +{ + namespace + { +#ifdef _WIN32 + const std::string LQUOTE("\'"); + const std::string RQUOTE("\'"); +#else + const std::string LQUOTE("‘"); + const std::string RQUOTE("’"); +#endif + } // namespace + +#if defined(__GNUC__) + // GNU GCC with -Weffc++ will issue a warning regarding the upcoming class, we want to silence it: + // warning: base class 'class std::enable_shared_from_this' has accessible non-virtual destructor + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" + #pragma GCC diagnostic ignored "-Weffc++" +// This will be ignored under other compilers like LLVM clang. +#endif + class Value : public std::enable_shared_from_this { + public: + virtual ~Value() = default; + + virtual std::shared_ptr clone() const = 0; + + virtual void parse(const std::string & text) const = 0; + + virtual void parse() const = 0; + + virtual bool has_default() const = 0; + + virtual bool is_container() const = 0; + + virtual bool has_implicit() const = 0; + + virtual std::string get_default_value() const = 0; + + virtual std::string get_implicit_value() const = 0; + + virtual std::shared_ptr default_value(const std::string & value) = 0; + + virtual std::shared_ptr implicit_value(const std::string & value) = 0; + + virtual std::shared_ptr no_implicit_value() = 0; + + virtual bool is_boolean() const = 0; + }; +#if defined(__GNUC__) + #pragma GCC diagnostic pop +#endif + class OptionException : public std::exception { + public: + explicit OptionException(std::string message) : m_message(std::move(message)) { } + + CXXOPTS_NODISCARD + const char * what() const noexcept override { return m_message.c_str(); } + + private: + std::string m_message; + }; + + class OptionSpecException : public OptionException { + public: + explicit OptionSpecException(const std::string & message) : OptionException(message) { } + }; + + class OptionParseException : public OptionException { + public: + explicit OptionParseException(const std::string & message) : OptionException(message) { } + }; + + class option_exists_error : public OptionSpecException { + public: + explicit option_exists_error(const std::string & option) + : OptionSpecException("Option " + LQUOTE + option + RQUOTE + " already exists") + { } + }; + + class invalid_option_format_error : public OptionSpecException { + public: + explicit invalid_option_format_error(const std::string & format) + : OptionSpecException("Invalid option format " + LQUOTE + format + RQUOTE) + { } + }; + + class option_syntax_exception : public OptionParseException { + public: + explicit option_syntax_exception(const std::string & text) + : OptionParseException("Argument " + LQUOTE + text + RQUOTE + " starts with a - but has incorrect syntax") + { } + }; + + class option_not_exists_exception : public OptionParseException { + public: + explicit option_not_exists_exception(const std::string & option) + : OptionParseException("Option " + LQUOTE + option + RQUOTE + " does not exist") + { } + }; + + class missing_argument_exception : public OptionParseException { + public: + explicit missing_argument_exception(const std::string & option) + : OptionParseException("Option " + LQUOTE + option + RQUOTE + " is missing an argument") + { } + }; + + class option_requires_argument_exception : public OptionParseException { + public: + explicit option_requires_argument_exception(const std::string & option) + : OptionParseException("Option " + LQUOTE + option + RQUOTE + " requires an argument") + { } + }; + + class option_not_has_argument_exception : public OptionParseException { + public: + option_not_has_argument_exception(const std::string & option, const std::string & arg) + : OptionParseException( + "Option " + LQUOTE + option + RQUOTE + " does not take an argument, but argument " + LQUOTE + arg + RQUOTE + + " given") + { } + }; + + class option_not_present_exception : public OptionParseException { + public: + explicit option_not_present_exception(const std::string & option) + : OptionParseException("Option " + LQUOTE + option + RQUOTE + " not present") + { } + }; + + class option_has_no_value_exception : public OptionException { + public: + explicit option_has_no_value_exception(const std::string & option) + : OptionException( + !option.empty() ? ("Option " + LQUOTE + option + RQUOTE + " has no value") : "Option has no value") + { } + }; + + class argument_incorrect_type : public OptionParseException { + public: + explicit argument_incorrect_type(const std::string & arg) + : OptionParseException("Argument " + LQUOTE + arg + RQUOTE + " failed to parse") + { } + }; + + class option_required_exception : public OptionParseException { + public: + explicit option_required_exception(const std::string & option) + : OptionParseException("Option " + LQUOTE + option + RQUOTE + " is required but not present") + { } + }; + + template void throw_or_mimic(const std::string & text) + { + static_assert( + std::is_base_of::value, + "throw_or_mimic only works on std::exception and " + "deriving classes"); + +#ifndef CXXOPTS_NO_EXCEPTIONS + // If CXXOPTS_NO_EXCEPTIONS is not defined, just throw + throw T {text}; +#else + // Otherwise manually instantiate the exception, print what() to stderr, + // and exit + T exception {text}; + std::cerr << exception.what() << std::endl; + std::exit(EXIT_FAILURE); +#endif + } + + namespace values + { + namespace parser_tool + { + struct IntegerDesc + { + std::string negative = ""; + std::string base = ""; + std::string value = ""; + }; + struct ArguDesc + { + std::string arg_name = ""; + bool grouping = false; + bool set_value = false; + std::string value = ""; + }; +#ifdef CXXOPTS_NO_REGEX + inline IntegerDesc SplitInteger(const std::string & text) + { + if(text.empty()) + { + throw_or_mimic(text); + } + IntegerDesc desc; + const char * pdata = text.c_str(); + if(*pdata == '-') + { + pdata += 1; + desc.negative = "-"; + } + if(strncmp(pdata, "0x", 2) == 0) + { + pdata += 2; + desc.base = "0x"; + } + if(*pdata != '\0') + { + desc.value = std::string(pdata); + } + else + { + throw_or_mimic(text); + } + return desc; + } + + inline bool IsTrueText(const std::string & text) + { + const char * pdata = text.c_str(); + if(*pdata == 't' || *pdata == 'T') + { + pdata += 1; + if(strncmp(pdata, "rue\0", 4) == 0) + { + return true; + } + } + else if(strncmp(pdata, "1\0", 2) == 0) + { + return true; + } + return false; + } + + inline bool IsFalseText(const std::string & text) + { + const char * pdata = text.c_str(); + if(*pdata == 'f' || *pdata == 'F') + { + pdata += 1; + if(strncmp(pdata, "alse\0", 5) == 0) + { + return true; + } + } + else if(strncmp(pdata, "0\0", 2) == 0) + { + return true; + } + return false; + } + + inline std::pair SplitSwitchDef(const std::string & text) + { + std::string short_sw, long_sw; + const char * pdata = text.c_str(); + if(isalnum(*pdata) && *(pdata + 1) == ',') + { + short_sw = std::string(1, *pdata); + pdata += 2; + } + while(*pdata == ' ') + { + pdata += 1; + } + if(isalnum(*pdata)) + { + const char * store = pdata; + pdata += 1; + while(isalnum(*pdata) || *pdata == '-' || *pdata == '_') + { + pdata += 1; + } + if(*pdata == '\0') + { + long_sw = std::string(store, pdata - store); + } + else + { + throw_or_mimic(text); + } + } + return std::pair(short_sw, long_sw); + } + + inline ArguDesc ParseArgument(const char * arg, bool & matched) + { + ArguDesc argu_desc; + const char * pdata = arg; + matched = false; + if(strncmp(pdata, "--", 2) == 0) + { + pdata += 2; + if(isalnum(*pdata)) + { + argu_desc.arg_name.push_back(*pdata); + pdata += 1; + while(isalnum(*pdata) || *pdata == '-' || *pdata == '_') + { + argu_desc.arg_name.push_back(*pdata); + pdata += 1; + } + if(argu_desc.arg_name.length() > 1) + { + if(*pdata == '=') + { + argu_desc.set_value = true; + pdata += 1; + if(*pdata != '\0') + { + argu_desc.value = std::string(pdata); + } + matched = true; + } + else if(*pdata == '\0') + { + matched = true; + } + } + } + } + else if(strncmp(pdata, "-", 1) == 0) + { + pdata += 1; + argu_desc.grouping = true; + while(isalnum(*pdata)) + { + argu_desc.arg_name.push_back(*pdata); + pdata += 1; + } + matched = !argu_desc.arg_name.empty() && *pdata == '\0'; + } + return argu_desc; + } + +#else // CXXOPTS_NO_REGEX + + namespace + { + + std::basic_regex integer_pattern("(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)"); + std::basic_regex truthy_pattern("(t|T)(rue)?|1"); + std::basic_regex falsy_pattern("(f|F)(alse)?|0"); + + std::basic_regex option_matcher("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)"); + std::basic_regex option_specifier("(([[:alnum:]]),)?[ ]*([[:alnum:]][-_[:alnum:]]*)?"); + + } // namespace + + inline IntegerDesc SplitInteger(const std::string & text) + { + std::smatch match; + std::regex_match(text, match, integer_pattern); + + if(match.length() == 0) + { + throw_or_mimic(text); + } + + IntegerDesc desc; + desc.negative = match[1]; + desc.base = match[2]; + desc.value = match[3]; + + if(match.length(4) > 0) + { + desc.base = match[5]; + desc.value = "0"; + return desc; + } + + return desc; + } + + inline bool IsTrueText(const std::string & text) + { + std::smatch result; + std::regex_match(text, result, truthy_pattern); + return !result.empty(); + } + + inline bool IsFalseText(const std::string & text) + { + std::smatch result; + std::regex_match(text, result, falsy_pattern); + return !result.empty(); + } + + inline std::pair SplitSwitchDef(const std::string & text) + { + std::match_results result; + std::regex_match(text.c_str(), result, option_specifier); + if(result.empty()) + { + throw_or_mimic(text); + } + + const std::string & short_sw = result[2]; + const std::string & long_sw = result[3]; + + return std::pair(short_sw, long_sw); + } + + inline ArguDesc ParseArgument(const char * arg, bool & matched) + { + std::match_results result; + std::regex_match(arg, result, option_matcher); + matched = !result.empty(); + + ArguDesc argu_desc; + if(matched) + { + argu_desc.arg_name = result[1].str(); + argu_desc.set_value = result[2].length() > 0; + argu_desc.value = result[3].str(); + if(result[4].length() > 0) + { + argu_desc.grouping = true; + argu_desc.arg_name = result[4].str(); + } + } + + return argu_desc; + } + +#endif // CXXOPTS_NO_REGEX +#undef CXXOPTS_NO_REGEX + } + + namespace detail + { + template struct SignedCheck; + + template struct SignedCheck + { + template void operator()(bool negative, U u, const std::string & text) + { + if(negative) + { + if(u > static_cast((std::numeric_limits::min)())) + { + throw_or_mimic(text); + } + } + else + { + if(u > static_cast((std::numeric_limits::max)())) + { + throw_or_mimic(text); + } + } + } + }; + + template struct SignedCheck + { + template void operator()(bool, U, const std::string &) const { } + }; + + template void check_signed_range(bool negative, U value, const std::string & text) + { + SignedCheck::is_signed>()(negative, value, text); + } + } // namespace detail + + template void checked_negate(R & r, T && t, const std::string &, std::true_type) + { + // if we got to here, then `t` is a positive number that fits into + // `R`. So to avoid MSVC C4146, we first cast it to `R`. + // See https://github.com/jarro2783/cxxopts/issues/62 for more details. + r = static_cast(-static_cast(t - 1) - 1); + } + + template void checked_negate(R &, T &&, const std::string & text, std::false_type) + { + throw_or_mimic(text); + } + + template void integer_parser(const std::string & text, T & value) + { + parser_tool::IntegerDesc int_desc = parser_tool::SplitInteger(text); + + using US = typename std::make_unsigned::type; + constexpr bool is_signed = std::numeric_limits::is_signed; + + const bool negative = int_desc.negative.length() > 0; + const uint8_t base = int_desc.base.length() > 0 ? 16 : 10; + const std::string & value_match = int_desc.value; + + US result = 0; + + for(char ch: value_match) + { + US digit = 0; + + if(ch >= '0' && ch <= '9') + { + digit = static_cast(ch - '0'); + } + else if(base == 16 && ch >= 'a' && ch <= 'f') + { + digit = static_cast(ch - 'a' + 10); + } + else if(base == 16 && ch >= 'A' && ch <= 'F') + { + digit = static_cast(ch - 'A' + 10); + } + else + { + throw_or_mimic(text); + } + + const US next = static_cast(result * base + digit); + if(result > next) + { + throw_or_mimic(text); + } + + result = next; + } + + detail::check_signed_range(negative, result, text); + + if(negative) + { + checked_negate(value, result, text, std::integral_constant()); + } + else + { + value = static_cast(result); + } + } + + template void stringstream_parser(const std::string & text, T & value) + { + std::stringstream in(text); + in >> value; + if(!in) + { + throw_or_mimic(text); + } + } + + template::value>::type * = nullptr> + void parse_value(const std::string & text, T & value) + { + integer_parser(text, value); + } + + inline void parse_value(const std::string & text, bool & value) + { + if(parser_tool::IsTrueText(text)) + { + value = true; + return; + } + + if(parser_tool::IsFalseText(text)) + { + value = false; + return; + } + + throw_or_mimic(text); + } + + inline void parse_value(const std::string & text, std::string & value) { value = text; } + + // The fallback parser. It uses the stringstream parser to parse all types + // that have not been overloaded explicitly. It has to be placed in the + // source code before all other more specialized templates. + template::value>::type * = nullptr> + void parse_value(const std::string & text, T & value) + { + stringstream_parser(text, value); + } + + template void parse_value(const std::string & text, std::vector & value) + { + if(text.empty()) + { + T v; + parse_value(text, v); + value.emplace_back(std::move(v)); + return; + } + std::stringstream in(text); + std::string token; + while(!in.eof() && std::getline(in, token, CXXOPTS_VECTOR_DELIMITER)) + { + T v; + parse_value(token, v); + value.emplace_back(std::move(v)); + } + } + +#ifdef CXXOPTS_HAS_OPTIONAL + template void parse_value(const std::string & text, std::optional & value) + { + T result; + parse_value(text, result); + value = std::move(result); + } +#endif + + inline void parse_value(const std::string & text, char & c) + { + if(text.length() != 1) + { + throw_or_mimic(text); + } + + c = text[0]; + } + + template struct type_is_container + { + static constexpr bool value = false; + }; + + template struct type_is_container> + { + static constexpr bool value = true; + }; + + template class abstract_value : public Value { + using Self = abstract_value; + + public: + abstract_value() : m_result(std::make_shared()), m_store(m_result.get()) { } + + explicit abstract_value(T * t) : m_store(t) { } + + ~abstract_value() override = default; + + abstract_value & operator=(const abstract_value &) = default; + + abstract_value(const abstract_value & rhs) + { + if(rhs.m_result) + { + m_result = std::make_shared(); + m_store = m_result.get(); + } + else + { + m_store = rhs.m_store; + } + + m_default = rhs.m_default; + m_implicit = rhs.m_implicit; + m_default_value = rhs.m_default_value; + m_implicit_value = rhs.m_implicit_value; + } + + void parse(const std::string & text) const override { parse_value(text, *m_store); } + + bool is_container() const override { return type_is_container::value; } + + void parse() const override { parse_value(m_default_value, *m_store); } + + bool has_default() const override { return m_default; } + + bool has_implicit() const override { return m_implicit; } + + std::shared_ptr default_value(const std::string & value) override + { + m_default = true; + m_default_value = value; + return shared_from_this(); + } + + std::shared_ptr implicit_value(const std::string & value) override + { + m_implicit = true; + m_implicit_value = value; + return shared_from_this(); + } + + std::shared_ptr no_implicit_value() override + { + m_implicit = false; + return shared_from_this(); + } + + std::string get_default_value() const override { return m_default_value; } + + std::string get_implicit_value() const override { return m_implicit_value; } + + bool is_boolean() const override { return std::is_same::value; } + + const T & get() const + { + if(m_store == nullptr) + { + return *m_result; + } + return *m_store; + } + + protected: + std::shared_ptr m_result {}; + T * m_store {}; + + bool m_default = false; + bool m_implicit = false; + + std::string m_default_value {}; + std::string m_implicit_value {}; + }; + + template class standard_value : public abstract_value { + public: + using abstract_value::abstract_value; + + CXXOPTS_NODISCARD + std::shared_ptr clone() const override { return std::make_shared>(*this); } + }; + + template<> class standard_value : public abstract_value { + public: + ~standard_value() override = default; + + standard_value() { set_default_and_implicit(); } + + explicit standard_value(bool * b) : abstract_value(b) { set_default_and_implicit(); } + + std::shared_ptr clone() const override { return std::make_shared>(*this); } + + private: + void set_default_and_implicit() + { + m_default = true; + m_default_value = "false"; + m_implicit = true; + m_implicit_value = "true"; + } + }; + } // namespace values + + template std::shared_ptr value() { return std::make_shared>(); } + + template std::shared_ptr value(T & t) { return std::make_shared>(&t); } + + class OptionAdder; + + class OptionDetails { + public: + OptionDetails(std::string short_, std::string long_, String desc, std::shared_ptr val) + : m_short(std::move(short_)), m_long(std::move(long_)), m_desc(std::move(desc)), m_value(std::move(val)), + m_count(0) + { + m_hash = std::hash {}(m_long + m_short); + } + + OptionDetails(const OptionDetails & rhs) + : m_desc(rhs.m_desc), m_value(rhs.m_value->clone()), m_count(rhs.m_count) + { } + + OptionDetails(OptionDetails && rhs) = default; + + CXXOPTS_NODISCARD + const String & description() const { return m_desc; } + + CXXOPTS_NODISCARD + const Value & value() const { return *m_value; } + + CXXOPTS_NODISCARD + std::shared_ptr make_storage() const { return m_value->clone(); } + + CXXOPTS_NODISCARD + const std::string & short_name() const { return m_short; } + + CXXOPTS_NODISCARD + const std::string & long_name() const { return m_long; } + + size_t hash() const { return m_hash; } + + private: + std::string m_short {}; + std::string m_long {}; + String m_desc {}; + std::shared_ptr m_value {}; + int m_count; + + size_t m_hash {}; + }; + + struct HelpOptionDetails + { + std::string s; + std::string l; + String desc; + bool has_default; + std::string default_value; + bool has_implicit; + std::string implicit_value; + std::string arg_help; + bool is_container; + bool is_boolean; + }; + + struct HelpGroupDetails + { + std::string name {}; + std::string description {}; + std::vector options {}; + }; + + class OptionValue { + public: + void parse(const std::shared_ptr & details, const std::string & text) + { + ensure_value(details); + ++m_count; + m_value->parse(text); + m_long_name = &details->long_name(); + } + + void parse_default(const std::shared_ptr & details) + { + ensure_value(details); + m_default = true; + m_long_name = &details->long_name(); + m_value->parse(); + } + + void parse_no_value(const std::shared_ptr & details) + { + m_long_name = &details->long_name(); + } + +#if defined(CXXOPTS_NULL_DEREF_IGNORE) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wnull-dereference" +#endif + + CXXOPTS_NODISCARD + size_t count() const noexcept { return m_count; } + +#if defined(CXXOPTS_NULL_DEREF_IGNORE) + #pragma GCC diagnostic pop +#endif + + // TODO: maybe default options should count towards the number of arguments + CXXOPTS_NODISCARD + bool has_default() const noexcept { return m_default; } + + template const T & as() const + { + if(m_value == nullptr) + { + throw_or_mimic(m_long_name == nullptr ? "" : *m_long_name); + } + +#ifdef CXXOPTS_NO_RTTI + return static_cast &>(*m_value).get(); +#else + return dynamic_cast &>(*m_value).get(); +#endif + } + + private: + void ensure_value(const std::shared_ptr & details) + { + if(m_value == nullptr) + { + m_value = details->make_storage(); + } + } + + const std::string * m_long_name = nullptr; + // Holding this pointer is safe, since OptionValue's only exist in key-value pairs, + // where the key has the string we point to. + std::shared_ptr m_value {}; + size_t m_count = 0; + bool m_default = false; + }; + + class KeyValue { + public: + KeyValue(std::string key_, std::string value_) : m_key(std::move(key_)), m_value(std::move(value_)) { } + + CXXOPTS_NODISCARD + const std::string & key() const { return m_key; } + + CXXOPTS_NODISCARD + const std::string & value() const { return m_value; } + + template T as() const + { + T result; + values::parse_value(m_value, result); + return result; + } + + private: + std::string m_key; + std::string m_value; + }; + + using ParsedHashMap = std::unordered_map; + using NameHashMap = std::unordered_map; + + class ParseResult { + public: + ParseResult() = default; + ParseResult(const ParseResult &) = default; + + ParseResult( + NameHashMap && keys, + ParsedHashMap && values, + std::vector sequential, + std::vector && unmatched_args) + : m_keys(std::move(keys)), m_values(std::move(values)), m_sequential(std::move(sequential)), + m_unmatched(std::move(unmatched_args)) + { } + + ParseResult & operator=(ParseResult &&) = default; + ParseResult & operator=(const ParseResult &) = default; + + size_t count(const std::string & o) const + { + auto iter = m_keys.find(o); + if(iter == m_keys.end()) + { + return 0; + } + + auto viter = m_values.find(iter->second); + + if(viter == m_values.end()) + { + return 0; + } + + return viter->second.count(); + } + + const OptionValue & operator[](const std::string & option) const + { + auto iter = m_keys.find(option); + + if(iter == m_keys.end()) + { + throw_or_mimic(option); + } + + auto viter = m_values.find(iter->second); + + if(viter == m_values.end()) + { + throw_or_mimic(option); + } + + return viter->second; + } + + const std::vector & arguments() const { return m_sequential; } + + const std::vector & unmatched() const { return m_unmatched; } + + private: + NameHashMap m_keys {}; + ParsedHashMap m_values {}; + std::vector m_sequential {}; + std::vector m_unmatched {}; + }; + + struct Option + { + Option( + std::string opts, + std::string desc, + std::shared_ptr value = ::cxxopts::value(), + std::string arg_help = "") + : opts_(std::move(opts)), desc_(std::move(desc)), value_(std::move(value)), arg_help_(std::move(arg_help)) + { } + + std::string opts_; + std::string desc_; + std::shared_ptr value_; + std::string arg_help_; + }; + + using OptionMap = std::unordered_map>; + using PositionalList = std::vector; + using PositionalListIterator = PositionalList::const_iterator; + + class OptionParser { + public: + OptionParser(const OptionMap & options, const PositionalList & positional, bool allow_unrecognised) + : m_options(options), m_positional(positional), m_allow_unrecognised(allow_unrecognised) + { } + + ParseResult parse(int argc, const char * const * argv); + + bool consume_positional(const std::string & a, PositionalListIterator & next); + + void checked_parse_arg( + int argc, + const char * const * argv, + int & current, + const std::shared_ptr & value, + const std::string & name); + + void add_to_option(OptionMap::const_iterator iter, const std::string & option, const std::string & arg); + + void parse_option( + const std::shared_ptr & value, + const std::string & name, + const std::string & arg = ""); + + void parse_default(const std::shared_ptr & details); + + void parse_no_value(const std::shared_ptr & details); + + private: + void finalise_aliases(); + + const OptionMap & m_options; + const PositionalList & m_positional; + + std::vector m_sequential {}; + bool m_allow_unrecognised; + + ParsedHashMap m_parsed {}; + NameHashMap m_keys {}; + }; + + class Options { + public: + explicit Options(std::string program, std::string help_string = "") + : m_program(std::move(program)), m_help_string(toLocalString(std::move(help_string))), + m_custom_help("[OPTION...]"), m_positional_help("positional parameters"), m_show_positional(false), + m_allow_unrecognised(false), m_width(76), m_tab_expansion(false), m_options(std::make_shared()) + { } + + Options & positional_help(std::string help_text) + { + m_positional_help = std::move(help_text); + return *this; + } + + Options & custom_help(std::string help_text) + { + m_custom_help = std::move(help_text); + return *this; + } + + Options & show_positional_help() + { + m_show_positional = true; + return *this; + } + + Options & allow_unrecognised_options() + { + m_allow_unrecognised = true; + return *this; + } + + Options & set_width(size_t width) + { + m_width = width; + return *this; + } + + Options & set_tab_expansion(bool expansion = true) + { + m_tab_expansion = expansion; + return *this; + } + + ParseResult parse(int argc, const char * const * argv); + + OptionAdder add_options(std::string group = ""); + + void add_options(const std::string & group, std::initializer_list

    +#include +#include +#include +#include +#include + +sqlite3 * OpenDatabase(std::string const & databaseFilePath) +{ + sqlite3 * connectionPtr; + if(sqlite3_open(databaseFilePath.c_str(), &connectionPtr) != SQLITE_OK) + { + throw std::runtime_error("Error opening SQLite3 database"); + } + sqlite3_extended_result_codes(connectionPtr, 1); + + return connectionPtr; +} + +std::string ToSqlInsertStatement(DSMR::Data const & data, time_t const time) +{ + std::stringstream ss; + ss << "INSERT INTO ElectricityLog VALUES('" << Util::GetSqliteDate(time) << "','" << Util::GetSqliteUtcTime(time) + << "'," << std::fixed << std::setprecision(2) << data.currentPowerUsageKw << ',' + << data.totalPowerConsumptionDayKwh << ',' << data.totalPowerConsumptionNightKwh << ',' + << data.currentPowerReturnKw << ',' << data.totalPowerReturnedDayKwh << ',' << data.totalPowerReturnedNightKwh + << ',' << data.usingDayTarif << ',' << data.gasConsumptionCubicMeters << ");"; + + return ss.str(); +} + +void Database::Insert(DSMR::Data const & data, time_t const time) +{ + std::stringstream transaction; + transaction << "BEGIN TRANSACTION;" << ToSqlInsertStatement(data, time) << "COMMIT;"; + + if(sqlite3_exec(connectionPtr, transaction.str().c_str(), nullptr, nullptr, nullptr) != SQLITE_OK) + { + spdlog::error("Failed to insert DSMR record into SQLite database: {}", sqlite3_errmsg(connectionPtr)); + throw std::runtime_error("Failed to insert DSMR record into SQLite databas"); + } +} + +Database::Database(std::string const & databaseFilePath) +{ + if(sqlite3_open(databaseFilePath.c_str(), &connectionPtr) != SQLITE_OK) + { + spdlog::error("Error whilst opening SQLite database {}", databaseFilePath); + throw std::runtime_error("Error opening SQLite3 database"); + } + sqlite3_extended_result_codes(connectionPtr, 1); +} + +Database::~Database() +{ + if(connectionPtr) + { + sqlite3_close(connectionPtr); + } +} diff --git a/src/electricity-logger/dsmr.cpp b/src/electricity-logger/dsmr.cpp new file mode 100644 index 0000000..36f647c --- /dev/null +++ b/src/electricity-logger/dsmr.cpp @@ -0,0 +1,174 @@ +#include +#include +#include + +namespace DSMR +{ + const std::unordered_map & Data::GetMap() + { + static std::unordered_map map = { + { "1-3:0.2.8", LineTag::DSMRversion }, + { "0-0:1.0.0", LineTag::DateTimeStamp }, + { "0-0:96.1.1", LineTag::SerialNo }, + { "1-0:1.8.1", LineTag::TotalPowerConsumedTariff1 }, + { "1-0:1.8.2", LineTag::TotalPowerConsumedTariff2 }, + { "1-0:2.8.1", LineTag::TotalReturnedPowerTariff1 }, + { "1-0:2.8.2", LineTag::TotalReturnedPowerTariff2 }, + { "0-0:96.14.0", LineTag::CurrentTarif }, // 1 == night, 2 == day, + { "1-0:1.7.0", LineTag::CurrentPowerConsumption }, + { "1-0:2.7.0", LineTag::CurrentPowerReturn }, + { "0-0:96.7.21", LineTag::PowerFailureCount }, + { "0-0:96.7.9", LineTag::PowerFailureLongCount }, + { "1-0:99.97.0", LineTag::PowerFailureEventLog }, + { "1-0:32.32.0", LineTag::VoltageL1SagCount }, + { "1-0:52.32.0", LineTag::VoltageL2SagCount }, + { "1-0:72.32.0", LineTag::VoltageL3SagCount }, + { "1-0:32.36.0", LineTag::VoltageL1SwellCount }, + { "1-0:52.36.0", LineTag::VoltageL2SwellCount }, + { "1-0:72.36.0", LineTag::VoltageL3SwellCount }, + { "0-0:96.13.0", LineTag::TextMessageMaxChar }, + { "1-0:32.7.0", LineTag::InstantL1VoltageResolution }, + { "1-0:52.7.0", LineTag::InstantL2VoltageResolution }, + { "1-0:72.7.0", LineTag::InstantL3VoltageResolution }, + { "1-0:31.7.0", LineTag::InstantL1CurrentResolution }, + { "1-0:51.7.0", LineTag::InstantL2CurrentResolution }, + { "1-0:71.7.0", LineTag::InstantL3CurrentResolution }, + { "1-0:21.7.0", LineTag::InstantL1ActivePowerResolution }, + { "1-0:41.7.0", LineTag::InstantL2ActivePowerResolution }, + { "1-0:61.7.0", LineTag::InstantL3ActivePowerResolution }, + { "1-0:22.7.0", LineTag::InstantL1ActivePowerResolutionA }, + { "1-0:42.7.0", LineTag::InstantL2ActivePowerResolutionA }, + { "1-0:62.7.0", LineTag::InstantL3ActivePowerResolutionA }, + { "0-1:24.1.0", LineTag::DeviceType }, + { "0-1:96.1.0", LineTag::GasDeviceIdentifier }, + { "0-1:24.2.1", LineTag::GasTotalConsumptionLog }, + }; + + return map; + } + + void Data::RemoveUnit(std::string & value) + { + const auto fresult = value.find('*'); + if(fresult == std::string::npos) + { + return; + } + value.resize(fresult); + } + + std::pair Data::GetKeyValuePair(const std::string & line) + { + const auto bracketOpen = line.find('('); + if(bracketOpen == std::string::npos) + { + return std::make_pair("", ""); + } + const auto bracketClose = line.find(')', bracketOpen); + if(bracketClose == std::string::npos) + { + return std::make_pair(line.substr(0, bracketOpen), ""); + } + + return std::make_pair( + line.substr(0, bracketOpen), + line.substr(bracketOpen + 1, bracketClose - (bracketOpen + 1))); + } + + void Data::ParseLine(const std::string & line) + { + const auto & map = GetMap(); + + auto pair = GetKeyValuePair(line); + auto & key = pair.first; + auto & value = pair.second; + + const auto fresult = map.find(key); + if(fresult == map.end()) + { + return; + } + + RemoveUnit(value); + std::stringstream ss; + ss.str(value); + + switch(fresult->second) + { + case LineTag::CurrentPowerConsumption: + ss >> currentPowerUsageKw; + break; + + case LineTag::CurrentPowerReturn: + ss >> currentPowerReturnKw; + break; + + case LineTag::TotalPowerConsumedTariff2: + ss >> totalPowerConsumptionDayKwh; + break; + + case LineTag::TotalPowerConsumedTariff1: + ss >> totalPowerConsumptionNightKwh; + break; + + case LineTag::TotalReturnedPowerTariff1: + ss >> totalPowerReturnedDayKwh; + break; + + case LineTag::TotalReturnedPowerTariff2: + ss >> totalPowerReturnedNightKwh; + break; + + case LineTag::CurrentTarif: + { + int tarif = 1; + ss >> tarif; + usingDayTarif = (tarif == 2); + } + break; + + case LineTag::GasTotalConsumptionLog: + ss >> gasTimestamp; + { + const auto secondBracket = line.find('(', key.size() + value.size() + 2); + if(secondBracket == std::string::npos) + { + break; + } + const auto unitSymbol = line.find('*', secondBracket); + if(secondBracket == std::string::npos) + { + break; + } + const std::string consumption = line.substr(secondBracket + 1, unitSymbol - (secondBracket + 1)); + ss.clear(); + ss.str(consumption); + ss >> gasConsumptionCubicMeters; + } + break; + + default: + break; + } + } + + void Data::ParseLines(const std::vector & lines) + { + for(const auto & line: lines) + { + ParseLine(line); + } + } + + std::string Data::GetFormattedString(char const separator) const + { + std::stringstream ss; + ss << currentPowerUsageKw << separator << totalPowerConsumptionDayKwh << separator + << totalPowerConsumptionNightKwh << separator << currentPowerReturnKw << separator + << totalPowerReturnedDayKwh << separator << totalPowerReturnedNightKwh << separator + << (usingDayTarif ? "day-tarif" : "night-tarif") << separator << gasTimestamp << separator + << gasConsumptionCubicMeters; + + return ss.str(); + } +} diff --git a/src/electricity-logger/main.cpp b/src/electricity-logger/main.cpp new file mode 100644 index 0000000..16abc87 --- /dev/null +++ b/src/electricity-logger/main.cpp @@ -0,0 +1,117 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +std::optional ExtractArgs(int argc, char ** argv) +{ + cxxopts::Options options( + "electricity-logger", + "electricity-logger is a small program that fetches power and gas statistics from an attached Landis Gyr E350 electricity meter and outputs this on stdout."); + + options.add_options()( + "d,serial-device", + "Absolute path to the serial device to read from", + cxxopts::value())( + "connection-string", + "Path to the sqlite3 database file", + cxxopts::value()); + + if(argc == 1) + { + std::cout << options.help() << std::endl; + return {}; + } + + try + { + auto const parsed = options.parse(argc, argv); + return parsed; + } + catch(cxxopts::OptionException const & e) + { + spdlog::error(e.what()); + return {}; + } +} + +DSMR::Data ReadData(std::string const & devicePath) +{ + char const * serialDeviceValue = devicePath.c_str(); + int fd = open(serialDeviceValue, O_RDONLY | O_NOCTTY | O_SYNC); + if(fd < 0) + { + spdlog::error("Error opening device {}", serialDeviceValue); + throw std::runtime_error("Error opening serial device for reading"); + } + SerialPort serial(fd); + + spdlog::info("Starting logging operation with serial device {}", serialDeviceValue); + + // Find the first line, which starts with a forward slash + bool waiting = true; + do + { + try + { + auto line = serial.ReadLine(); + if(line.size() > 0 && line[0] == '/') + { + waiting = false; + } + } + catch(std::exception const & ex) + { + spdlog::error("Error whilst seeking first output line from device {}: {}", serialDeviceValue, ex.what()); + throw std::runtime_error("Error reading from serial device"); + } + } while(waiting); + + // We reached the interesting bits, parse them and keep what we want + DSMR::Data data; + int i = 1; + while(i < 37) + { + try + { + auto line = serial.ReadLine(); + if(line.size() > 5) + { + data.ParseLine(line); + ++i; + } + } + catch(std::exception const & ex) + { + spdlog::error("Error whilst parsing line from device {}: {}", serialDeviceValue, ex.what()); + throw std::runtime_error("Error parsing data from serial device"); + } + } + + return data; +} + +int main(int argc, char ** argv) +{ + auto const maybeArgs = ExtractArgs(argc, argv); + if(!maybeArgs.has_value()) + { + return 1; + } + + auto const & args = maybeArgs.value(); + + auto const data = ReadData(args["serial-device"].as()); + + auto const connectionStringValue = args["connection-string"].as(); + Database db(connectionStringValue); + db.Insert(data, std::time(nullptr)); + + return 0; +} diff --git a/src/electricity-logger/serialport.cpp b/src/electricity-logger/serialport.cpp new file mode 100644 index 0000000..83d7b48 --- /dev/null +++ b/src/electricity-logger/serialport.cpp @@ -0,0 +1,55 @@ +#include +#include +#include +#include + +void SerialPort::SetAttributes(const speed_t baudrate) +{ + cfsetospeed(&configuration, baudrate); + cfsetispeed(&configuration, baudrate); + + configuration.c_cflag = (configuration.c_cflag & ~CSIZE) | CS8; // 8 bit chars + configuration.c_iflag &= ~IGNBRK; + configuration.c_lflag = 0; + configuration.c_oflag = 0; + configuration.c_cc[VMIN] = 0; // no blocking read + configuration.c_cc[VTIME] = 5; + + configuration.c_iflag &= ~(IXON | IXOFF | IXANY); + configuration.c_cflag |= (CLOCAL | CREAD); + configuration.c_cflag &= ~(PARENB | PARODD); + configuration.c_cflag &= ~(CSTOPB | CRTSCTS); + + if(tcsetattr(device, TCSANOW, &configuration) != 0) + { + throw std::runtime_error("Error setting configuration of device."); + } +} + +std::string SerialPort::ReadLine() +{ + std::string retval; + char c; + while(read(device, &c, 1) == 1) + { + retval += c; + if(c == '\n') + break; + } + + return retval; +} + +SerialPort::SerialPort(const int fd) : device(fd) +{ + memset(&configuration, 0, sizeof(termios)); + if(tcgetattr(fd, &configuration) != 0) + { + throw std::runtime_error("Error getting attributes from file descriptor."); + } + oldConfiguration = configuration; + + SetAttributes(); +} + +SerialPort::~SerialPort() { tcsetattr(device, TCSANOW, &oldConfiguration); } diff --git a/src/electricity-server/main.cpp b/src/electricity-server/main.cpp new file mode 100644 index 0000000..84ac38f --- /dev/null +++ b/src/electricity-server/main.cpp @@ -0,0 +1,51 @@ +#include +#include +#include +#include + +int main(int argc, char ** argv) +{ + TCLAP::CmdLine cmd( + "electricity-server is a small Pistache based HTTP content server with a REST API to access the solar log database", + ' ', + "1.0.0"); + + TCLAP::ValueArg + listeningPortArg("p", "listening-port", "TCP listening port number", true, 0u, "TCP listening port number"); + cmd.add(listeningPortArg); + + TCLAP::ValueArg logDirectoryPath( + "d", + "data-directory", + "Absolute path pointing to the logging directory", + true, + "", + "Absolute path pointing to the logging directory"); + cmd.add(logDirectoryPath); + + TCLAP::ValueArg serverDomain( + "s", + "server-domain", + "Domain this server is hosted on", + true, + "", + "Domain this server is hosted on"); + cmd.add(serverDomain); + + cmd.parse(argc, argv); + + auto & config = Server::Configuration::Get(); + config.Setup(logDirectoryPath.getValue(), serverDomain.getValue()); + + Pistache::Address address(Pistache::Ipv4::any(), listeningPortArg.getValue()); + Pistache::Http::Endpoint server(address); + + auto options = Pistache::Http::Endpoint::options().threads(2); + server.init(options); + + Pistache::Rest::Router router; + Server::Api::SetupRouting(router); + server.setHandler(router.handler()); + + server.serve(); +} \ No newline at end of file diff --git a/src/electricity-server/server/api.cpp b/src/electricity-server/server/api.cpp new file mode 100644 index 0000000..c1de18a --- /dev/null +++ b/src/electricity-server/server/api.cpp @@ -0,0 +1,96 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Server::Api +{ + using Pistache::Http::Mime::Subtype; + using Pistache::Http::Mime::Type; + + // Only allow serving to ourselves, all behind the same NAT address + bool IsRequesteeAllowed(Pistache::Http::Request const & request) + { + Configuration & config = Configuration::Get(); + auto const & serverAddress = config.GetExternalServerIp(); + + auto realIpHeader = request.headers().tryGetRaw("X-Real-IP"); + if(realIpHeader.isEmpty()) + { + spdlog::error("Blocking request without X-Real-IP header"); + return false; + } + + if(realIpHeader.unsafeGet().value() != serverAddress) + { + spdlog::info( + "Blocking request {} due to host mismatch (expected {})", + realIpHeader.unsafeGet().value(), + serverAddress); + return false; + } + + return true; + } + + void GetDay(Pistache::Http::Request const & request, Pistache::Http::ResponseWriter responseWrite) + { + spdlog::info( + "{} {} {}", + Pistache::Http::methodString(request.method()), + request.resource(), + request.query().as_str()); + + if(!IsRequesteeAllowed(request)) + { + responseWrite.send(Pistache::Http::Code::Unauthorized); + return; + } + + auto const startQuery = request.query().get("start"); + if(startQuery.isEmpty()) + { + responseWrite.send(Pistache::Http::Code::Bad_Request); + return; + } + + Util::Date const startDate(startQuery.unsafeGet()); + if(!startDate.IsValid()) + { + responseWrite.send(Pistache::Http::Code::Bad_Request); + return; + } + + auto const stopQuery = request.query().get("stop"); + if(stopQuery.isEmpty()) + { + responseWrite.send( + Pistache::Http::Code::Ok, + Database::GetDetailedJsonOf(startDate), + MIME(Application, Json)); + return; + } + + Util::Date const stopDate(stopQuery.unsafeGet()); + if(!stopDate.IsValid() || stopDate.IsBefore(startDate)) + { + responseWrite.send(Pistache::Http::Code::Bad_Request); + return; + } + + responseWrite.send( + Pistache::Http::Code::Ok, + Database::GetSummaryJsonOf(startDate, stopDate), + MIME(Application, Json)); + } + + void SetupRouting(Pistache::Rest::Router & router) + { + Pistache::Rest::Routes::Get(router, "/day", Pistache::Rest::Routes::bind(&GetDay)); + } +} \ No newline at end of file diff --git a/src/electricity-server/server/configuration.cpp b/src/electricity-server/server/configuration.cpp new file mode 100644 index 0000000..3ffcba2 --- /dev/null +++ b/src/electricity-server/server/configuration.cpp @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include +#include +#include + +namespace Server +{ + Configuration::Configuration() : logDirectory() { } + + void Configuration::RefreshExternalIp() + { + addrinfo hints; + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + hints.ai_protocol = 0; + hints.ai_canonname = nullptr; + hints.ai_addr = nullptr; + hints.ai_next = nullptr; + + addrinfo * serverInfo; + auto const result = getaddrinfo(serverDomain.c_str(), "http", &hints, &serverInfo); + if(result) + { + spdlog::error( + "Error {} when parsing domain {} to determine external IP address", + gai_strerror(result), + serverDomain); + lastExternalIp.clear(); + return; + } + + char addressBuffer[INET_ADDRSTRLEN]; + sockaddr_in * socketAddress = reinterpret_cast(serverInfo->ai_addr); + if(inet_ntop(AF_INET, &socketAddress->sin_addr, addressBuffer, INET_ADDRSTRLEN) != nullptr) + { + lastIpCheckTimePoint = std::chrono::steady_clock::now(); + lastExternalIp = std::string(addressBuffer); + spdlog::info("External IP address {} cached", lastExternalIp); + } + else + { + auto const error = errno; + spdlog::error("Error {} returned by inet_ntop when trying to determine external IP address", error); + lastExternalIp.clear(); + } + + freeaddrinfo(serverInfo); + return; + } + + bool Configuration::ExternalIpRequiresRefresh() const + { + if(!std::regex_match(lastExternalIp, std::regex("^([0-9]+\\.){3}[0-9]+$"))) + { + return true; + } + + auto timeSinceLastRefresh = std::chrono::steady_clock::now() - lastIpCheckTimePoint; + return timeSinceLastRefresh >= std::chrono::minutes(5); + } + + void Configuration::Setup(std::string & electricityLogDirectory, std::string const & _serverDomain) + { + logDirectory = electricityLogDirectory; + if(electricityLogDirectory.size() > 0 && electricityLogDirectory[electricityLogDirectory.size() - 1] != '/') + { + logDirectory += '/'; + } + + serverDomain = _serverDomain; + } + + std::string const & Configuration::GetLogDirectory() const { return logDirectory; } + + std::string const & Configuration::GetExternalServerIp() + { + if(ExternalIpRequiresRefresh()) + { + std::lock_guard lock(externalIpRefreshMutex); + if(ExternalIpRequiresRefresh()) + { + RefreshExternalIp(); + } + } + + return lastExternalIp; + } + + Configuration & Configuration::Get() + { + static Configuration c; + return c; + } +} \ No newline at end of file diff --git a/src/electricity-server/server/database.cpp b/src/electricity-server/server/database.cpp new file mode 100644 index 0000000..48bdf0a --- /dev/null +++ b/src/electricity-server/server/database.cpp @@ -0,0 +1,211 @@ +#include +#include +#include +#include +#include +#include +#include + +namespace Server::Database +{ + struct Record + { + private: + bool isValid; + + public: + long epoch; + double currentPowerUsage; + double totalPowerUsageDay; + double totalPowerUsageNight; + double currentPowerReturn; + double totalPowerReturnDay; + double totalPowerReturnNight; + double totalGasUsage; + + bool IsValid() const { return isValid; } + + void AppendAsJson(std::stringstream & ss) const + { + ss << "{\"dateTime\":" << epoch << ",\"totalPowerUse\":" << totalPowerUsageDay + totalPowerUsageNight + << ",\"totalPowerReturn\":" << totalPowerReturnDay + totalPowerReturnNight + << ",\"totalGasUse\":" << totalGasUsage << '}'; + } + + Record() + : isValid(false), currentPowerUsage(0.0), totalPowerUsageDay(0.0), totalPowerUsageNight(0.0), + currentPowerReturn(0.0), totalPowerReturnDay(0.0), totalPowerReturnNight(0.0), totalGasUsage(0.0) + { } + + Record(std::string const & line) + : isValid(false), currentPowerUsage(0.0), totalPowerUsageDay(0.0), totalPowerUsageNight(0.0), + currentPowerReturn(0.0), totalPowerReturnDay(0.0), totalPowerReturnNight(0.0), totalGasUsage(0.0) + { + std::vector values; + + char const delimiter = ','; + std::size_t previousIndex = 0; + while(true) + { + auto const commaIndex = line.find(delimiter, previousIndex + 1); + if(commaIndex != std::string::npos) + { + values.push_back(line.substr(previousIndex, commaIndex - previousIndex)); + previousIndex = commaIndex + 1; + } + else + { + break; + } + } + + if(previousIndex < line.size()) + { + values.push_back(line.substr(previousIndex)); + } + + if(values.size() != 10) + { + return; + } + + Util::Date const date(values[0]); + if(!date.IsValid()) + { + return; + } + int hours, minutes, seconds; + if(std::sscanf(values[0].substr(11).c_str(), "%d:%d:%d", &hours, &minutes, &seconds) != 3) + { + return; + } + + /* Fields are separated by comma's and represent: + 1 datetime + 2 currentPowerUsage (kw) + 3 totalPowerConsumptionDay (kwh) + 4 totalPowerConsumptionNight (kwh) + 5 currentPowerReturn (kw) + 6 totalPowerReturnedDay (kwh) + 7 totalPowerReturnedNight (kwh) + 8 tarif type (unused) + 9 gas timestamp (unused) + 10 gas consumption (M^3) + */ + epoch = date.ToEpoch() + hours * 3600 + minutes * 60 + seconds - 3600; + currentPowerUsage = std::atof(values[1].c_str()); + totalPowerUsageDay = std::atof(values[2].c_str()); + totalPowerUsageNight = std::atof(values[3].c_str()); + currentPowerReturn = std::atof(values[4].c_str()); + totalPowerReturnDay = std::atof(values[5].c_str()); + totalPowerReturnNight = std::atof(values[6].c_str()); + totalGasUsage = std::atof(values[9].c_str()); + + isValid = true; + } + }; + + std::string GetFileName(Util::Date const & date) + { + std::stringstream filePath; + filePath << Configuration::Get().GetLogDirectory() << date.Year() << '/' << std::setw(2) << std::setfill('0') + << date.Month() << '_' << std::setw(2) << date.Day() << ".txt"; + + return filePath.str(); + } + + std::vector GetFileContents(Util::Date const & date) + { + std::ifstream logFile(GetFileName(date)); + if(!logFile.is_open()) + { + return std::vector(); + } + + std::vector retval; + std::string line; + while(std::getline(logFile, line)) + { + Record record(line); + if(record.IsValid()) + { + retval.push_back(record); + } + } + logFile.close(); + + return retval; + } + + std::string GetDetailedJsonOf(Util::Date const & date) + { + auto const records = GetFileContents(date); + std::stringstream json; + json << '['; + + bool first = true; + for(std::size_t i = 0; i < records.size(); ++i) + { + if(!first) + { + json << ','; + } + first = false; + + records[i].AppendAsJson(json); + } + + json << ']'; + return json.str(); + } + + bool GetSummaryJsonOf(Util::Date const & date, bool const prependComma, std::stringstream & json) + { + if(prependComma) + { + json << ','; + } + + auto const records = GetFileContents(date); + if(records.size() < 2) + { + Record record; + record.epoch = date.ToEpoch(); + + record.AppendAsJson(json); + + return false; + } + + auto const firstRecord = records[0]; + auto lastRecord = records[records.size() - 1]; + lastRecord.totalPowerUsageDay -= firstRecord.totalPowerUsageDay; + lastRecord.totalPowerUsageNight -= firstRecord.totalPowerUsageNight; + lastRecord.totalPowerReturnDay -= firstRecord.totalPowerReturnDay; + lastRecord.totalPowerReturnNight -= firstRecord.totalPowerReturnNight; + lastRecord.totalGasUsage -= firstRecord.totalGasUsage; + + lastRecord.AppendAsJson(json); + + return true; + } + + std::string GetSummaryJsonOf(Util::Date const & startDate, Util::Date const & stopDate) + { + std::stringstream json; + json << '['; + + long const dayInSeconds = 24 * 60 * 60; + long const start = startDate.ToEpoch(); + long const stop = stopDate.ToEpoch(); + bool first = true; + for(long current = start; current <= stop; current += dayInSeconds) + { + GetSummaryJsonOf(Util::Date(current), !first, json); + first = false; + } + + json << ']'; + return json.str(); + } +} \ No newline at end of file diff --git a/src/migrator/main.cpp b/src/migrator/main.cpp new file mode 100644 index 0000000..63a1df0 --- /dev/null +++ b/src/migrator/main.cpp @@ -0,0 +1,32 @@ +#include +#include +#include + +int main(int argc, char ** argv) +{ + TCLAP::CmdLine cmd("migrator is a small program designed to run migrations", ' ', "1.0"); + + TCLAP::ValueArg migrationArg("m", "migration", "", true, "", "Name of the migration to run"); + cmd.add(migrationArg); + + TCLAP::ValueArg srcArg("s", "source", "", false, "", "Source file or directory to use"); + cmd.add(srcArg); + + TCLAP::ValueArg dstArg("d", "destination", "", false, "", "Destination file or directory to use"); + cmd.add(dstArg); + + cmd.parse(argc, argv); + + auto const & migrationToRun = migrationArg.getValue(); + if(migrationToRun == "epochToDateTime") + { + return Migrations::EpochToDateTime(srcArg.getValue(), dstArg.getValue()); + } + if(migrationToRun == "updateSummaryTable") + { + return Migrations::UpdateSummaryTable(srcArg.getValue(), dstArg.getValue()); + } + + std::printf("Unknown migration %s, aborting.\n", migrationToRun.c_str()); + return 1; +} \ No newline at end of file diff --git a/src/migrator/migrations/epochtodatetime.cpp b/src/migrator/migrations/epochtodatetime.cpp new file mode 100644 index 0000000..133a20a --- /dev/null +++ b/src/migrator/migrations/epochtodatetime.cpp @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include + +std::string ZeroPadTwoDigitNumber(int number) +{ + auto result = std::to_string(number); + if(result.size() == 1) + { + return "0" + result; + } + + return result; +} + +int SourceCallback(void * data, int argc, char ** argv, char ** columnNames) +{ + if(argc != 3) + { + std::puts("Expected source database to have 3 columns: DateTimeUtc, Watt and KilowattHour."); + return 1; + } + + Transaction * const transactionPtr = reinterpret_cast(data); + auto const epochTime = std::atol(argv[0]); + auto const dateTime = *std::gmtime(&epochTime); + + std::stringstream insertStream; + insertStream << "INSERT INTO SolarPanelOutput VALUES(" << '\'' << (dateTime.tm_year + 1900) << '-' + << ZeroPadTwoDigitNumber(dateTime.tm_mon + 1) << '-' << ZeroPadTwoDigitNumber(dateTime.tm_mday) + << "','" << ZeroPadTwoDigitNumber(dateTime.tm_hour) << ':' << ZeroPadTwoDigitNumber(dateTime.tm_min) + << ':' << ZeroPadTwoDigitNumber(dateTime.tm_sec) << "'," << argv[1] << ',' << argv[2] << ");"; + + transactionPtr->AddStatement(insertStream.str()); + + if(transactionPtr->StatementCount() > 1000) + { + return transactionPtr->Execute(); + } + + return 0; +} + +namespace Migrations +{ + int EpochToDateTime(std::string const & sourceDatabase, std::string const & destinationDatabase) + { + if(sourceDatabase == destinationDatabase) + { + std::puts("The EpochToDateTime is not meant to be run on the same database."); + return 1; + } + + sqlite3 * source; + if(sqlite3_open(sourceDatabase.c_str(), &source)) + { + std::printf("Error opening source database %s\n", sourceDatabase.c_str()); + return 1; + } + + sqlite3 * destination; + if(sqlite3_open(destinationDatabase.c_str(), &destination)) + { + std::printf("Error opening destination database %s\n", destinationDatabase.c_str()); + return 1; + } + + Transaction transaction(destination); + auto const sqlResult + = sqlite3_exec(source, "SELECT * FROM SolarPanelOutput;", SourceCallback, &transaction, nullptr); + if(sqlResult) + { + std::printf("Error %i during insertion of records into destination database\n", sqlResult); + return 1; + } + + auto const commitResult = transaction.Execute(); + if(commitResult) + { + std::printf("Error %i when committing last transaction\n", commitResult); + return 1; + } + + sqlite3_close(source); + sqlite3_close(destination); + + return 0; + } +} diff --git a/src/migrator/migrations/updatesummarytable.cpp b/src/migrator/migrations/updatesummarytable.cpp new file mode 100644 index 0000000..1165185 --- /dev/null +++ b/src/migrator/migrations/updatesummarytable.cpp @@ -0,0 +1,68 @@ +#include +#include +#include + +namespace Migrations +{ + int SourceCallback(void * data, int argc, char ** argv, char ** columnNames) + { + // Expect Date and KilowattHour + if(argc != 2) + { + std::puts("Wrong number of columns received"); + return 1; + } + + Transaction * transactionPtr = reinterpret_cast(data); + std::stringstream insertStream; + insertStream << "INSERT INTO SolarPanelSummary(Date,KilowattHour) VALUES(" << '\'' << argv[0] << "'," << argv[1] + << ')' << "ON CONFLICT(Date) DO UPDATE SET KilowattHour = excluded.KilowattHour;"; + + transactionPtr->AddStatement(insertStream.str()); + + return 0; + } + + int UpdateSummaryTable(std::string const & sourceDatabase, std::string const & destinationDatabase) + { + sqlite3 * source; + if(sqlite3_open(sourceDatabase.c_str(), &source)) + { + std::printf("Error opening source database %s\n", sourceDatabase.c_str()); + return 1; + } + + sqlite3 * destination; + if(sqlite3_open(destinationDatabase.c_str(), &destination)) + { + std::printf("Error opening destination database %s\n", destinationDatabase.c_str()); + return 1; + } + + Transaction transaction(destination); + auto const sqlResult = sqlite3_exec( + source, + "SELECT Date, MAX(KilowattHour) AS KilowattHour FROM SolarPanelOutput GROUP BY Date;", + SourceCallback, + &transaction, + nullptr); + if(sqlResult) + { + std::printf("Error %i during fetching of source database records\n", sqlResult); + return 1; + } + + std::printf("UpdateSummaryTable: Upserting %u records...\n", transaction.StatementCount()); + auto const commitResult = transaction.Execute(); + if(commitResult) + { + std::printf("Error %i when committing transaction\n", commitResult); + return 1; + } + + sqlite3_close(source); + sqlite3_close(destination); + + return 0; + } +} \ No newline at end of file diff --git a/src/migrator/transaction.cpp b/src/migrator/transaction.cpp new file mode 100644 index 0000000..523ccf7 --- /dev/null +++ b/src/migrator/transaction.cpp @@ -0,0 +1,35 @@ +#include + +void Transaction::Reset() +{ + queryStream.clear(); + queryStream.str(std::string()); + queryCount = 0u; + + queryStream << "PRAGMA journal_mode = OFF;" + << "BEGIN TRANSACTION;"; +} + +void Transaction::AddStatement(std::string const & statement) +{ + ++queryCount; + queryStream << statement; +} + +unsigned Transaction::StatementCount() const { return queryCount; } + +int Transaction::Execute() +{ + queryStream << "COMMIT;"; + + auto const result = sqlite3_exec(destination, queryStream.str().c_str(), nullptr, nullptr, nullptr); + Reset(); + + return result; +} + +Transaction::Transaction(sqlite3 * const databaseToInsertIn) + : destination(databaseToInsertIn), queryCount(0u), queryStream() +{ + Reset(); +} \ No newline at end of file diff --git a/src/solar-logger/database.cpp b/src/solar-logger/database.cpp new file mode 100644 index 0000000..6bcd763 --- /dev/null +++ b/src/solar-logger/database.cpp @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include +#include + +std::string Database::ToSqlInsertStatement(Row const & row) const +{ + std::stringstream ss; + ss << "INSERT INTO SolarPanelOutput VALUES(" << '\'' << Util::GetSqliteDate(row.epochTime) << "'," << '\'' + << Util::GetSqliteUtcTime(row.epochTime) << "'," << row.watt << ", " << std::fixed << std::setprecision(2) + << row.kilowattPerHour << ");"; + + return ss.str(); +} + +std::string Database::ToSqlUpsertStatement(Row const & row) const +{ + std::stringstream ss; + ss << "INSERT INTO SolarPanelSummary(Date,KilowattHour) VALUES(" << '\'' << Util::GetSqliteDate(row.epochTime) + << "'," << std::fixed << std::setprecision(2) << row.kilowattPerHour << ')' + << "ON CONFLICT(Date) DO UPDATE SET KilowattHour = excluded.KilowattHour WHERE excluded.KilowattHour > SolarPanelSummary.KilowattHour;"; + + return ss.str(); +} + +bool Database::Insert(Row & row) +{ + std::stringstream transaction; + transaction << "BEGIN TRANSACTION;" << ToSqlInsertStatement(row) << ToSqlUpsertStatement(row) << "COMMIT;"; + + return sqlite3_exec(connectionPtr, transaction.str().c_str(), nullptr, nullptr, nullptr); +} + +Database::Database(std::string const & databasePath) : connectionPtr(nullptr) +{ + if(sqlite3_open(databasePath.c_str(), &connectionPtr) != SQLITE_OK) + { + throw std::runtime_error("Error opening SQLite3 database"); + } + + sqlite3_extended_result_codes(connectionPtr, 1); +} + +Database::~Database() +{ + if(connectionPtr) + { + sqlite3_close(connectionPtr); + } +} diff --git a/src/solar-logger/main.cpp b/src/solar-logger/main.cpp new file mode 100644 index 0000000..e126a8c --- /dev/null +++ b/src/solar-logger/main.cpp @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char ** argv) +{ + TCLAP::CmdLine cmd( + "solar-logger is a small program that retrieves solarpower generation statistics from Zeverlution Sxxxx smart power inverters and stores it into a database", + ' ', + "1.0"); + + TCLAP::ValueArg urlArg( + "u", + "url", + "Fully qualified URL path and protocol to the home.cgi resource", + true, + "", + "Fully qualified URL path and protocol to the home.cgi resource"); + cmd.add(urlArg); + + TCLAP::ValueArg + timeoutArg("t", "timeout", "Fetch time out in milliseconds", false, 1000U, "Fetch time out in milliseconds"); + cmd.add(timeoutArg); + + TCLAP::ValueArg databasePathArg( + "d", + "database-path", + "Absolute path pointing to the solar SQLite *.db file", + true, + "", + "Absolute path pointing to the solar SQLite *.db file"); + cmd.add(databasePathArg); + + cmd.parse(argc, argv); + + ZeverData zeverData; + if(!zeverData.FetchDataFromURL(urlArg.getValue(), timeoutArg.getValue())) + { + return -1; + } + + Row row; + row.epochTime = std::time(nullptr); // now + row.watt = zeverData.watt; + row.kilowattPerHour = zeverData.kilowattPerHour; + + Database db(databasePathArg.getValue()); + auto const insertionResult = db.Insert(row); + if(insertionResult) + { + std::printf("Error %i during insertion of new value into database\n", insertionResult); + return -1; + } + + return 0; +} diff --git a/src/solar-logger/zeverdata.cpp b/src/solar-logger/zeverdata.cpp new file mode 100644 index 0000000..315fc35 --- /dev/null +++ b/src/solar-logger/zeverdata.cpp @@ -0,0 +1,88 @@ +#include + +namespace detail +{ + // libcurl callback + size_t write_to_string(void * ptr, size_t size, size_t nmemb, void * stream) + { + std::string line((char *)ptr, nmemb); + std::string * buffer = (std::string *)stream; + buffer->append(line); + + return nmemb * size; + } +} + +bool ZeverData::ParseString(const std::string & str) +{ + bool isValid = true; + std::stringstream ss; + ss.str(str); + + ss >> number0; + ss >> number1; + ss >> registeryID; + ss >> registeryKey; + ss >> hardwareVersion; + std::string versionInfo; + ss >> versionInfo; + size_t splitPos = versionInfo.find('+'); + appVersion = versionInfo.substr(0, splitPos); + ++splitPos; + wifiVersion = versionInfo.substr(splitPos, versionInfo.size()); + + ss >> timeValue; + ss >> dateValue; + ss >> zeverCloudStatus; + ss >> number3; + ss >> inverterSN; + isValid = (ss >> watt && ss >> kilowattPerHour); + ss >> OKmsg; + ss >> ERRORmsg; + + if(!isValid) + { + std::fprintf(stderr, "Error during parsing of zever data:\n%s\n", str.c_str()); + return false; + } + + return true; +} + +bool ZeverData::FetchDataFromURL(const std::string & url, const unsigned int timeout) +{ + curl_global_init(CURL_GLOBAL_ALL); + + CURL * curl = curl_easy_init(); + + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L); + //curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + std::string buffer; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, detail::write_to_string); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer); + + curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, timeout); + + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + + buffer.reserve(256); + if(curl_easy_perform(curl)) + { + watt = 0; + kilowattPerHour = 0.0; + + std::fprintf(stderr, "Failed to fetch zever data from URL <%s>!\n", url.c_str()); + + curl_easy_cleanup(curl); + return false; + } + + buffer.shrink_to_fit(); + + curl_easy_cleanup(curl); + + return ParseString(buffer); +} + +ZeverData::ZeverData() : watt(0), kilowattPerHour(0.0) { } diff --git a/src/solar-server/api.cpp b/src/solar-server/api.cpp new file mode 100644 index 0000000..bd2eb0c --- /dev/null +++ b/src/solar-server/api.cpp @@ -0,0 +1,93 @@ +#include +#include +#include + +namespace Api +{ + using Pistache::Http::Mime::Subtype; + using Pistache::Http::Mime::Type; + + Util::Date ParseUtcDate(std::string const & date, Util::Date const & fallbackValue) + { + Util::Date result; + if(!result.TryParse(date)) + { + return fallbackValue; + } + + return result; + } + + Util::Date ParseUtcDate(Pistache::Optional const & date, Util::Date const & fallbackValue) + { + if(date.isEmpty() || date.unsafeGet().size() != 10) + { + return fallbackValue; + } + + return ParseUtcDate(date.unsafeGet(), fallbackValue); + } + + void GetDay(Pistache::Http::Request const & request, Pistache::Http::ResponseWriter responseWrite) + { + Util::Date const start = ParseUtcDate(request.query().get("start"), Util::Date::UtcNow()); + auto const stopQuery = request.query().get("stop"); + if(stopQuery.isEmpty()) + { + responseWrite.send( + Pistache::Http::Code::Ok, + Configuration::Get().GetDatabaseConnection().GetEntireDay(start), + MIME(Application, Json)); + return; + } + + Util::Date const stop = ParseUtcDate(request.query().get("stop"), start); + if(!start.IsBefore(stop)) + { + responseWrite.send(Pistache::Http::Code::Bad_Request); + return; + } + + responseWrite.send( + Pistache::Http::Code::Ok, + Configuration::Get().GetDatabaseConnection().GetSummarizedPerDayRecords(start, stop), + MIME(Application, Json)); + } + + void GetMonth(Pistache::Http::Request const & request, Pistache::Http::ResponseWriter responseWrite) + { + auto const startQuery = request.query().get("start"); + auto const stopQuery = request.query().get("stop"); + if(startQuery.isEmpty() || stopQuery.isEmpty()) + { + responseWrite.send(Pistache::Http::Code::Bad_Request); + return; + } + + auto const start = Util::Date(startQuery.unsafeGet()); + auto stop = Util::Date(stopQuery.unsafeGet()); + if(!start.IsValid() || !stop.IsValid()) + { + responseWrite.send(Pistache::Http::Code::Bad_Request); + return; + } + + stop.SetDayToEndOfMonth(); + if(stop.IsBefore(start)) + { + responseWrite.send(Pistache::Http::Code::Bad_Request); + return; + } + + responseWrite.send( + Pistache::Http::Code::Ok, + Configuration::Get().GetDatabaseConnection().GetSummarizedPerMonthRecords(start, stop), + MIME(Application, Json)); + } + + void SetupRouting(Pistache::Rest::Router & router) + { + Pistache::Rest::Routes::Get(router, "/day", Pistache::Rest::Routes::bind(&Api::GetDay)); + Pistache::Rest::Routes::Get(router, "/month", Pistache::Rest::Routes::bind(&Api::GetMonth)); + } +} diff --git a/src/solar-server/configuration.cpp b/src/solar-server/configuration.cpp new file mode 100644 index 0000000..5b68929 --- /dev/null +++ b/src/solar-server/configuration.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +Configuration::Configuration() : database() { } + +Configuration & Configuration::SetupDatabase(std::string const & filePath) +{ + if(!database.Connect(filePath)) + { + throw std::runtime_error("Cannot open SQLite database at " + filePath); + } + + return *this; +} + +Database::Connection Configuration::GetDatabaseConnection() const { return database.GetConnection(); } + +Configuration & Configuration::Get() +{ + static Configuration c; + + return c; +} \ No newline at end of file diff --git a/src/solar-server/database/connection.cpp b/src/solar-server/database/connection.cpp new file mode 100644 index 0000000..e9fc6ba --- /dev/null +++ b/src/solar-server/database/connection.cpp @@ -0,0 +1,241 @@ +#include +#include +#include +#include +#include +#include + +namespace Database +{ + Connection::Connection(sqlite3 * const databaseConnectionPtr) : connectionPtr(databaseConnectionPtr) { } + + class JsonResult { + private: + long dateEpoch; + std::stringstream jsonStream; + unsigned insertions; + + void Reset() + { + insertions = 0u; + + jsonStream.clear(); + jsonStream.str(std::string()); + jsonStream << std::fixed << std::setprecision(2); + jsonStream << '['; + } + + public: + bool AddRecord(long const epoch, char const * watt, char const * kwh) + { + ++insertions; + jsonStream << "{\"time\":" << epoch << ",\"watt\":" << watt << ",\"kwh\":" << kwh << "},"; + + return true; + } + + bool AddRecord(char const * timeUtc, char const * watt, char const * kwh) + { + auto const timeInSeconds = Util::ToSecondsFromTimeString(timeUtc); + if(timeInSeconds < 0) + { + std::printf("AddRecord: cannot parse %s to hours, minutes and seconds\n", timeUtc); + return false; + } + + return AddRecord(timeInSeconds + dateEpoch, watt, kwh); + } + + bool + AddRecord(unsigned const year, unsigned const month, unsigned const day, char const * watt, char const * kwh) + { + return AddRecord(Util::GetEpoch(year, month, day), watt, kwh); + } + + // Returns the records added thus far as JSON array and resets + // itself to an empty array afterwards. + std::string GetJsonArray() + { + if(insertions) + { + // Replace last inserted comma + jsonStream.seekp(-1, std::ios_base::end); + jsonStream << ']'; + } + else + { + jsonStream << ']'; + } + + auto const result = jsonStream.str(); + Reset(); + return result; + } + + JsonResult(long _dateEpoch) : dateEpoch(_dateEpoch), jsonStream(), insertions(0u) { Reset(); } + }; + + int DetailedCallback(void * data, int argc, char ** argv, char ** columnNames) + { + // TimeUtc, Watt and KilowattHour + if(argc != 3) + { + std::printf("DetailedCallback: unexpected number of arguments %i\n", argc); + return -1; + } + + JsonResult * result = reinterpret_cast(data); + result->AddRecord(argv[0], argv[1], argv[2]); + + return 0; + } + + std::string Connection::GetEntireDay(Util::Date const & date) + { + std::stringstream queryStream; + queryStream << "SELECT TimeUtc, Watts, KilowattHour FROM SolarPanelOutput WHERE Date = " << '\'' + << date.ToISOString() << '\'' << " ORDER BY TimeUtc ASC;"; + + JsonResult result(date.ToEpoch()); + auto const sqlResult + = sqlite3_exec(connectionPtr, queryStream.str().c_str(), DetailedCallback, &result, nullptr); + if(sqlResult) + { + std::printf("GetEntireDay: SQLite error code %i, returning empty JSON array.\n", sqlResult); + return "[]"; + } + + return result.GetJsonArray(); + } + + int SummaryCallback(void * data, int argc, char ** argv, char ** columnNames) + { + // Date and KilowattHour + if(argc != 2) + { + std::printf("SummaryCallback: unexpected number of arguments %i\n", argc); + return -1; + } + + JsonResult * result = reinterpret_cast(data); + Util::Date recordDate(argv[0]); + result->AddRecord(recordDate.Year(), recordDate.Month(), recordDate.Day(), "0", argv[1]); + + return 0; + } + + std::string Connection::GetSummarizedPerDayRecords(Util::Date const & startDate, Util::Date const & endDate) + { + std::stringstream queryStream; + queryStream << "SELECT Date, KilowattHour FROM SolarPanelSummary" + << " WHERE Date >= '" << startDate.ToISOString() << '\'' << " AND Date <= '" + << endDate.ToISOString() << '\'' << " ORDER BY Date;"; + + JsonResult result(0); + auto const sqlResult + = sqlite3_exec(connectionPtr, queryStream.str().c_str(), SummaryCallback, &result, nullptr); + if(sqlResult) + { + std::printf("GetSummarizedPerDayRecords: SQLite error code %i, returning empty JSON array.\n", sqlResult); + return "[]"; + } + + return result.GetJsonArray(); + } + + struct YearResult + { + int year; + std::array monthValues; + + // month is in range 1 to 12 + void AddMonthValue(int month, double value) { monthValues[month - 1] += value; } + + YearResult(int _year) : year(_year), monthValues() { } + }; + + int MonthSummaryCallback(void * data, int argc, char ** argv, char ** columnNames) + { + // Date and KilowattHour + if(argc != 2) + { + std::printf("MonthSummaryCallback: unexpected number of arguments %i\n", argc); + return -1; + } + + Util::Date recordDate; + if(!recordDate.TryParse(argv[0])) + { + std::printf("MonthSummaryCallback: error parsing date %s\n", argv[0]); + return -1; + } + + std::vector & yearResults = *reinterpret_cast *>(data); + double const kwh = std::atof(argv[1]); + if(std::isnan(kwh) || kwh < 0.0) + { + // This value makes no sense, ignore it + std::printf("MonthSummaryCallback: ignoring bogus value for year month %s\n", argv[1]); + return 0; + } + + for(std::size_t i = 0; i < yearResults.size(); ++i) + { + if(yearResults[i].year == recordDate.Year()) + { + yearResults[i].AddMonthValue(recordDate.Month(), kwh); + return 0; + } + if(yearResults[i].year > recordDate.Year()) + { + yearResults.insert(yearResults.begin() + i, YearResult(recordDate.Year())); + yearResults[i].AddMonthValue(recordDate.Month(), kwh); + return 0; + } + } + + yearResults.push_back(YearResult(recordDate.Year())); + yearResults[yearResults.size() - 1].AddMonthValue(recordDate.Month(), kwh); + + return 0; + } + + std::string Connection::GetSummarizedPerMonthRecords(Util::Date const & startDate, Util::Date const & endDate) + { + std::stringstream queryStream; + queryStream << "SELECT Date, KilowattHour FROM SolarPanelSummary" + << " WHERE Date >= '" << startDate.ToISOString() << '\'' << " AND Date <= '" + << endDate.ToISOString() << "';"; + + std::vector yearResults; + auto const sqlResult + = sqlite3_exec(connectionPtr, queryStream.str().c_str(), MonthSummaryCallback, &yearResults, nullptr); + if(sqlResult || yearResults.size() == 0) + { + std::printf( + "GetSummarizedPerMonthRecords: SQLite return code %i and %lu years retrieved, returning empty JSON array.\n", + sqlResult, + yearResults.size()); + return "[]"; + } + + JsonResult result(0); + for(std::size_t i = 0; i < yearResults.size(); ++i) + { + auto const year = yearResults[i].year; + for(int month = 0; month < yearResults[i].monthValues.size(); ++month) + { + if(startDate.IsAfter(year, month + 1, 1) || endDate.IsBefore(year, month + 1, 1)) + { + continue; + } + + auto const epoch = Util::GetEpoch(year, month + 1, 1); + auto const kwh = yearResults[i].monthValues[month]; + result.AddRecord(epoch, "0", std::to_string(kwh).c_str()); + } + } + + return result.GetJsonArray(); + } +} \ No newline at end of file diff --git a/src/solar-server/database/database.cpp b/src/solar-server/database/database.cpp new file mode 100644 index 0000000..181baac --- /dev/null +++ b/src/solar-server/database/database.cpp @@ -0,0 +1,33 @@ +#include + +namespace Database +{ + bool Database::Connect(std::string const & path) + { + if(connectionPtr) + { + // Already connected + return true; + } + + if(sqlite3_open(path.c_str(), &connectionPtr)) + { + return false; + } + + sqlite3_extended_result_codes(connectionPtr, 1); + return true; + } + + Connection Database::GetConnection() const { return Connection(connectionPtr); } + + Database::Database() : connectionPtr(nullptr) { } + + Database::~Database() + { + if(connectionPtr) + { + sqlite3_close(connectionPtr); + } + } +} diff --git a/src/solar-server/main.cpp b/src/solar-server/main.cpp new file mode 100644 index 0000000..29a60ba --- /dev/null +++ b/src/solar-server/main.cpp @@ -0,0 +1,42 @@ +#include +#include +#include +#include + +int main(int argc, char ** argv) +{ + TCLAP::CmdLine cmd( + "solar-server is a small Pistache based HTTP content server with a REST API to access the solar log database", + ' ', + "1.0.0"); + + TCLAP::ValueArg + listeningPortArg("p", "listening-port", "TCP listening port number", true, 0u, "TCP listening port number"); + cmd.add(listeningPortArg); + + TCLAP::ValueArg databaseFileArg( + "d", + "database-file", + "Absolute path pointing to the solar SQLite *.db file", + true, + "", + "Absolute path pointing to the solar SQLite *.db file"); + cmd.add(databaseFileArg); + + cmd.parse(argc, argv); + + Configuration & config = Configuration::Get(); + config.SetupDatabase(databaseFileArg.getValue()); + + Pistache::Address address(Pistache::Ipv4::any(), listeningPortArg.getValue()); + Pistache::Http::Endpoint server(address); + + auto options = Pistache::Http::Endpoint::options().threads(2); + server.init(options); + + Pistache::Rest::Router router; + Api::SetupRouting(router); + server.setHandler(router.handler()); + + server.serve(); +} \ No newline at end of file diff --git a/systemd/electricity-server.service b/systemd/electricity-server.service new file mode 100644 index 0000000..c932627 --- /dev/null +++ b/systemd/electricity-server.service @@ -0,0 +1,13 @@ +[Unit] +Description=A pistache based HTTP server serving the Electricity API +Requires=network.target +After=network.target + +[Service] +Type=simple +ExecStart=/usr/local/bin/electricity-server -d /mnt/data0/log/electricity -p 3002 -s electricity.valkendaal.duckdns.org +Restart=always +RestartSec=30 + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/systemd/solar-server.service b/systemd/solar-server.service new file mode 100644 index 0000000..f2011aa --- /dev/null +++ b/systemd/solar-server.service @@ -0,0 +1,13 @@ +[Unit] +Description=A pistache based HTTP server serving the Solar API +Requires=network.target +After=network.target + +[Service] +Type=simple +ExecStart=/usr/local/bin/solar-server -d /mnt/data0/log/solarpaneloutput.db -p 3001 +Restart=always +RestartSec=30 + +[Install] +WantedBy=multi-user.target \ No newline at end of file