Skip to content

Commit 613b98e

Browse files
committed
Made ready for flasher.aandewiel.nl
1 parent 636d622 commit 613b98e

52 files changed

Lines changed: 6763 additions & 3942 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.clang-format

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
BasedOnStyle: LLVM
2+
IndentWidth: 2
3+
TabWidth: 2
4+
UseTab: Never
5+
BreakBeforeBraces: Allman
6+
AllowShortIfStatementsOnASingleLine: Never
7+
AllowShortLoopsOnASingleLine: false
8+
AllowShortFunctionsOnASingleLine: None
9+
ColumnLimit: 0
10+
PointerAlignment: Left
11+
SpaceBeforeParens: ControlStatements
12+
SortIncludes: Never

.codingRules.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Coding Rules
2+
3+
- AI assistant requirement: Always read this file first and apply all rules at the start of every new chat/session.
4+
5+
- Use the Allman coding style.
6+
- Use lowerCamelCase naming for variables and functions.
7+
- Use 2 spaces for indentation.
8+
- Place comments above variables and functions using the format: `//-- `
9+
- Write all comments in English.
10+
- Keep `README.md` always in English.
11+
- Keep all user-facing and internal code messages in English.
12+
- Keep the `setup()` and `loop()` functions as the last functions in the code.
13+
- Keep `Aandewiel` exactly as written in names; never convert it to lowerCamelCase.
14+
- Treat `PROG_VERSION` as a literal string; never convert it to lowerCamelCase.
15+
- In C/C++ code, prefer `std::string` instead of Arduino `String` where possible.
16+
- In C/C++ code, prefer `Serial.printf()` and `snprintf()` where possible.
17+
- Never remove empty lines or skip code sections.
18+
- For code changes and suggestions, never show only a few lines: always provide complete functions. For new code, clearly indicate where it should be placed by showing the existing lines before and after.

.github/workflows/tag-release.yml

Lines changed: 335 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,335 @@
1+
# -------------------------------------------------------------------------------
2+
#
3+
#-- Version Date: 25-02-2026 -- (dd-mm-eeyy)
4+
#
5+
# GitHub Actions workflow: Auto tag and manage GitHub Releases based on a version
6+
# string found in your PlatformIO firmware source file.
7+
#
8+
# Intended use
9+
# - PlatformIO/embedded projects where the firmware version is defined in source
10+
# code (example format below).
11+
# - On every push to the main/master branch, the workflow reads the version, compares it
12+
# to the latest existing semver tag (vX.Y.Z), and (if newer) creates a new tag.
13+
#
14+
# Version format expected in source file
15+
# - The workflow extracts the version from:
16+
# <PROGRAM_DIR>/<PROGRAM_SRC>
17+
# by searching for a PROG_VERSION line and extracting only:
18+
# vX.Y.Z
19+
# from examples like:
20+
# const char* PROG_VERSION = "v1.2.3 <and more text ..>";
21+
# const char* PROG_VERSION = v1.2.3 <and more text ..>;
22+
#
23+
# Tagging rules
24+
# - If the extracted version is newer than the latest semver tag in the repo:
25+
# - Create and push a Git tag "vX.Y.Z".
26+
# - If the version change is:
27+
# - Major (X increases) OR Minor (Y increases): create a GitHub Release.
28+
# - Patch-only (Z increases): create only a tag, no GitHub Release.
29+
#
30+
# Release-notes rule (important)
31+
# - When a GitHub Release is created, its body is composed of commit messages
32+
# since the previous GitHub Release tag (not since the previous tag).
33+
# - Example:
34+
# - v1.0.0 Release contains commit messages 1..4
35+
# - v2.0.0 Release contains commit messages 5..N
36+
# - Implementation detail:
37+
# - The workflow queries GitHub Releases to find the previous release tag,
38+
# then runs:
39+
# git log <previousReleaseTag>..HEAD --pretty=format:"- %s"
40+
#
41+
# Release retention rules
42+
# - "Main" releases (vX.0.0) are kept for every major.
43+
# - For each major, only one "minor" release (vX.Y.0 where Y>0) is kept:
44+
# - When creating a new minor release v3.3.0, it deletes GitHub Releases
45+
# v3.1.0 and v3.2.0 (if they exist), but keeps all tags.
46+
# - When creating a new major release v4.0.0, it deletes all minor releases
47+
# from older majors (e.g. deletes v3.2.0 release), but keeps tags.
48+
# - Patch releases are not created by this workflow. If patch releases exist
49+
# for some reason, this workflow leaves them untouched.
50+
#
51+
# Required repository settings
52+
# - Settings -> Actions -> General -> Workflow permissions:
53+
# - Set to "Read and write permissions" (contents: write).
54+
# -------------------------------------------------------------------------------
55+
56+
name: Auto Tag Release
57+
58+
env:
59+
PROGRAM_NAME: "DSMRloggerAPI"
60+
PROGRAM_SRC: "DSMRloggerAPI.cpp"
61+
PROGRAM_DIR: "src"
62+
63+
on:
64+
push:
65+
branches:
66+
- main
67+
- master
68+
69+
jobs:
70+
tag:
71+
runs-on: ubuntu-latest
72+
73+
permissions:
74+
contents: write
75+
76+
steps:
77+
- name: Checkout code
78+
uses: actions/checkout@v3
79+
80+
- name: Get version from ${{ env.PROGRAM_SRC }}
81+
id: getVersion
82+
run: |
83+
versionLine=$(grep -m1 'PROG_VERSION' ${{ env.PROGRAM_DIR }}/${{ env.PROGRAM_SRC }} || true)
84+
version=$(echo "$versionLine" | grep -Eo 'v[0-9]+\.[0-9]+\.[0-9]+' | head -n 1 || true)
85+
parseError=""
86+
87+
if [ -z "$versionLine" ]; then
88+
parseError="No PROG_VERSION line found in ${{ env.PROGRAM_DIR }}/${{ env.PROGRAM_SRC }}."
89+
elif [ -z "$version" ]; then
90+
parseError="PROG_VERSION line found, but no semantic version (vX.Y.Z) was detected."
91+
fi
92+
93+
echo "Detected PROG_VERSION line: $versionLine"
94+
echo "Extracted tag version: $version"
95+
if [ -n "$parseError" ]; then
96+
echo "::error::$parseError"
97+
fi
98+
99+
echo "VERSION=$version" >> $GITHUB_OUTPUT
100+
echo "VERSION=$version" >> $GITHUB_ENV
101+
echo "VERSION_PARSE_ERROR=$parseError" >> $GITHUB_OUTPUT
102+
echo "VERSION_PARSE_ERROR=$parseError" >> $GITHUB_ENV
103+
104+
- name: Fetch all tags
105+
run: git fetch --tags
106+
107+
- name: Get latest semver tag
108+
id: latestTag
109+
run: |
110+
latest=$(git tag --sort=-v:refname | grep -E '^v([0-9]+\.){2}[0-9]+$' | head -n 1 || true)
111+
echo "Latest tag detected: $latest"
112+
echo "LATEST=$latest" >> $GITHUB_OUTPUT
113+
114+
- name: Compare version
115+
id: compareVersion
116+
run: |
117+
version="${{ steps.getVersion.outputs.VERSION }}"
118+
versionParseError="${{ steps.getVersion.outputs.VERSION_PARSE_ERROR }}"
119+
latest="${{ steps.latestTag.outputs.LATEST }}"
120+
121+
echo "Comparing source version $version with latest tag $latest"
122+
123+
if [ -n "$versionParseError" ]; then
124+
echo "::error::$versionParseError"
125+
echo "PROCEED=false" >> $GITHUB_ENV
126+
exit 0
127+
fi
128+
129+
if [ -z "$version" ]; then
130+
echo "::error::No version found in ${{ env.PROGRAM_DIR }}/${{ env.PROGRAM_SRC }}. Skipping."
131+
echo "PROCEED=false" >> $GITHUB_ENV
132+
exit 0
133+
fi
134+
135+
if [ -z "$latest" ]; then
136+
echo "No existing tag found. Proceeding."
137+
echo "PROCEED=true" >> $GITHUB_ENV
138+
echo "MAKE_RELEASE=true" >> $GITHUB_ENV
139+
elif [ "$version" = "$latest" ]; then
140+
echo "::warning::Version $version already exists. Skipping."
141+
echo "PROCEED=false" >> $GITHUB_ENV
142+
elif [ "$(printf '%s\n' "$latest" "$version" | sort -V | head -n 1)" = "$version" ]; then
143+
echo "::warning::Version $version is not greater than $latest. Skipping."
144+
echo "PROCEED=false" >> $GITHUB_ENV
145+
else
146+
echo "Version $version is newer than $latest. Proceeding."
147+
echo "PROCEED=true" >> $GITHUB_ENV
148+
149+
versionMajor=$(echo "$version" | sed -E 's/^v([0-9]+)\..*/\1/')
150+
versionMinor=$(echo "$version" | sed -E 's/^v[0-9]+\.([0-9]+)\..*/\1/')
151+
latestMajor=$(echo "$latest" | sed -E 's/^v([0-9]+)\..*/\1/')
152+
latestMinor=$(echo "$latest" | sed -E 's/^v[0-9]+\.([0-9]+)\..*/\1/')
153+
154+
echo "Parsed version: $versionMajor.$versionMinor, latest: $latestMajor.$latestMinor"
155+
156+
# Treat major 0 as "always release" (SemVer: 0.y.z is unstable; any bump can be breaking)
157+
if [ "$versionMajor" -eq 0 ]; then
158+
echo "Major is 0. Any new version under v0.*.* will create a GitHub Release."
159+
echo "MAKE_RELEASE=true" >> $GITHUB_ENV
160+
elif [ "$versionMajor" -gt "$latestMajor" ] || [ "$versionMajor" -eq "$latestMajor" -a "$versionMinor" -gt "$latestMinor" ]; then
161+
echo "Major or minor version changed. A GitHub Release will be created."
162+
echo "MAKE_RELEASE=true" >> $GITHUB_ENV
163+
else
164+
echo "Only patch version changed. Only a tag will be created."
165+
echo "MAKE_RELEASE=false" >> $GITHUB_ENV
166+
fi
167+
fi
168+
169+
- name: Create and push tag
170+
if: env.PROCEED == 'true' && env.VERSION != ''
171+
run: |
172+
echo "Creating and pushing tag $VERSION"
173+
git config user.name "GitHub Actions"
174+
git config user.email "actions@github.com"
175+
git tag "$VERSION"
176+
git push origin "$VERSION"
177+
178+
- name: Determine previous release tag
179+
if: env.MAKE_RELEASE == 'true' && env.PROCEED == 'true'
180+
id: previousRelease
181+
env:
182+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
183+
run: |
184+
set -euo pipefail
185+
186+
version="${{ env.VERSION }}"
187+
repo="${GITHUB_REPOSITORY}"
188+
189+
echo "Finding previous GitHub Release tag (excluding $version)."
190+
191+
releasesJson=$(curl -sS \
192+
-H "Authorization: Bearer $GITHUB_TOKEN" \
193+
-H "Accept: application/vnd.github+json" \
194+
"https://api.github.com/repos/$repo/releases?per_page=100")
195+
196+
previousReleaseTag=$(
197+
echo "$releasesJson" \
198+
| jq -r '.[].tag_name' \
199+
| grep -E '^v([0-9]+\.){2}[0-9]+$' \
200+
| grep -v -F "$version" \
201+
| sort -V \
202+
| tail -n 1 \
203+
|| true
204+
)
205+
206+
if [ -z "$previousReleaseTag" ]; then
207+
echo "No previous GitHub Release tag found. This will be treated as the first release."
208+
else
209+
echo "Previous GitHub Release tag: $previousReleaseTag"
210+
fi
211+
212+
echo "PREVIOUS_RELEASE_TAG=$previousReleaseTag" >> $GITHUB_OUTPUT
213+
echo "PREVIOUS_RELEASE_TAG=$previousReleaseTag" >> $GITHUB_ENV
214+
215+
- name: Cleanup old minor releases (keep tags)
216+
if: env.MAKE_RELEASE == 'true' && env.PROCEED == 'true'
217+
env:
218+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
219+
run: |
220+
set -euo pipefail
221+
222+
version="${{ env.VERSION }}"
223+
repo="${GITHUB_REPOSITORY}"
224+
225+
versionMajor=$(echo "$version" | sed -E 's/^v([0-9]+)\..*/\1/')
226+
versionMinor=$(echo "$version" | sed -E 's/^v[0-9]+\.([0-9]+)\..*/\1/')
227+
versionPatch=$(echo "$version" | sed -E 's/^v[0-9]+\.[0-9]+\.([0-9]+)$/\1/')
228+
229+
isMajorRelease=false
230+
isMinorRelease=false
231+
232+
if [ "$versionMinor" -eq 0 ] && [ "$versionPatch" -eq 0 ]; then
233+
isMajorRelease=true
234+
elif [ "$versionMinor" -gt 0 ] && [ "$versionPatch" -eq 0 ]; then
235+
isMinorRelease=true
236+
fi
237+
238+
echo "Current version is $version (major=$versionMajor minor=$versionMinor patch=$versionPatch)"
239+
echo "Major release: $isMajorRelease"
240+
echo "Minor release: $isMinorRelease"
241+
242+
if [ "$isMajorRelease" = "false" ] && [ "$isMinorRelease" = "false" ]; then
243+
echo "This is not a major/minor .0 release. No cleanup needed."
244+
exit 0
245+
fi
246+
247+
releasesJson=$(curl -sS \
248+
-H "Authorization: Bearer $GITHUB_TOKEN" \
249+
-H "Accept: application/vnd.github+json" \
250+
"https://api.github.com/repos/$repo/releases?per_page=100")
251+
252+
releaseCount=$(echo "$releasesJson" | jq 'length')
253+
echo "Fetched $releaseCount releases."
254+
255+
releaseIdsToDelete=()
256+
257+
if [ "$isMajorRelease" = "true" ]; then
258+
echo "Deleting minor releases from older majors."
259+
while IFS=$'\t' read -r tagName releaseId; do
260+
if [[ "$tagName" =~ ^v([0-9]+)\.([0-9]+)\.0$ ]]; then
261+
tagMajor="${BASH_REMATCH[1]}"
262+
tagMinor="${BASH_REMATCH[2]}"
263+
if [ "$tagMinor" -gt 0 ] && [ "$tagMajor" -lt "$versionMajor" ]; then
264+
echo "Scheduled for deletion: release tag $tagName (releaseId=$releaseId)"
265+
releaseIdsToDelete+=("$releaseId")
266+
fi
267+
fi
268+
done < <(echo "$releasesJson" | jq -r '.[] | [.tag_name, .id] | @tsv')
269+
270+
elif [ "$isMinorRelease" = "true" ]; then
271+
echo "Deleting older minor releases within the same major."
272+
while IFS=$'\t' read -r tagName releaseId; do
273+
if [[ "$tagName" =~ ^v([0-9]+)\.([0-9]+)\.0$ ]]; then
274+
tagMajor="${BASH_REMATCH[1]}"
275+
tagMinor="${BASH_REMATCH[2]}"
276+
if [ "$tagMajor" -eq "$versionMajor" ] && [ "$tagMinor" -gt 0 ] && [ "$tagMinor" -lt "$versionMinor" ]; then
277+
echo "Scheduled for deletion: release tag $tagName (releaseId=$releaseId)"
278+
releaseIdsToDelete+=("$releaseId")
279+
fi
280+
fi
281+
done < <(echo "$releasesJson" | jq -r '.[] | [.tag_name, .id] | @tsv')
282+
fi
283+
284+
if [ "${#releaseIdsToDelete[@]}" -eq 0 ]; then
285+
echo "No releases matched the cleanup rules."
286+
exit 0
287+
fi
288+
289+
for releaseId in "${releaseIdsToDelete[@]}"; do
290+
echo "Deleting GitHub Release id=$releaseId (tags will be kept)."
291+
curl -sS -X DELETE \
292+
-H "Authorization: Bearer $GITHUB_TOKEN" \
293+
-H "Accept: application/vnd.github+json" \
294+
"https://api.github.com/repos/$repo/releases/$releaseId" >/dev/null
295+
done
296+
297+
echo "Cleanup completed. All tags were preserved."
298+
299+
- name: Generate release notes
300+
if: env.MAKE_RELEASE == 'true' && env.PROCEED == 'true'
301+
id: releaseNotes
302+
run: |
303+
version="${{ env.VERSION }}"
304+
previousReleaseTag="${{ env.PREVIOUS_RELEASE_TAG }}"
305+
306+
echo "Generating release notes for $version"
307+
echo "## Changes" > release_notes.txt
308+
echo "" >> release_notes.txt
309+
310+
if [ -z "$previousReleaseTag" ]; then
311+
echo "No previous GitHub Release tag found. Including recent commits (max 20)."
312+
git log --pretty=format:"- %s" | head -n 20 >> release_notes.txt
313+
echo "" >> release_notes.txt
314+
echo "" >> release_notes.txt
315+
echo "_First release_" >> release_notes.txt
316+
else
317+
echo "Including commits since previous GitHub Release tag $previousReleaseTag."
318+
echo "### Changes since $previousReleaseTag" >> release_notes.txt
319+
echo "" >> release_notes.txt
320+
git log ${previousReleaseTag}..HEAD --pretty=format:"- %s" >> release_notes.txt
321+
fi
322+
323+
echo "Release notes file created."
324+
325+
- name: Create GitHub Release
326+
if: env.MAKE_RELEASE == 'true' && env.PROCEED == 'true'
327+
uses: actions/create-release@v1
328+
env:
329+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
330+
with:
331+
tag_name: ${{ env.VERSION }}
332+
release_name: Release ${{ env.VERSION }}
333+
body_path: release_notes.txt
334+
draft: false
335+
prerelease: false

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ data/RINGdays.csv
66
data/RINGhours.csv
77
data/RINGmonths.csv
88
.DS_Store
9-
9+
projects
1010

.vscode/c_cpp_properties.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@
123123
]
124124
},
125125
"defines": [
126-
"PLATFORMIO=60115",
126+
"PLATFORMIO=60119",
127127
"ESP8266",
128128
"ARDUINO_ARCH_ESP8266",
129129
"ARDUINO_ESP8266_ESP12",

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ There is a new permutation of the hard- and software that you can find [here](ht
1616

1717
<table>
1818
<tr><th>Versie</th><th align="Left">Opmerking</th></tr>
19+
<tr>
20+
<td valign="top">3.0.5</td>
21+
<td>Ready for flasher.aandewiel.nl
22+
<br>_FW_VERSION is now PROG_VERSION to comply with tag-release.py
23+
</td>
24+
</tr>
1925
<tr>
2026
<td valign="top">3.0.4</td>
2127
<td>"One Fits All" Release

0 commit comments

Comments
 (0)