From 08b845f792b407dcffe2effe83af12ca24cc61cc Mon Sep 17 00:00:00 2001 From: marcel Date: Wed, 28 Feb 2024 16:30:15 +0100 Subject: [PATCH] Heater algoritm now 10/10min, was 5/15min --- CHANGELOG.md | 6 + article/Makefile | 9 + article/css/mvp.css | 563 + article/images/weather_station_schematic.svg | 33282 +++++++++++++++++ article/template/custom_settings.tex | 16 + article/template/template.html | 120 + article/weather_station_article.html | 205 + article/weather_station_article.md | 71 + build-doc/weather_station.html | 12 +- build-doc/weather_station.md | 4 +- build-doc/weather_station.pdf | Bin 1825276 -> 1825536 bytes build-doc/weather_station_article.md | 57 + firmware/weather_station.ino | 8 +- 13 files changed, 34342 insertions(+), 11 deletions(-) create mode 100644 article/Makefile create mode 100644 article/css/mvp.css create mode 100644 article/images/weather_station_schematic.svg create mode 100644 article/template/custom_settings.tex create mode 100644 article/template/template.html create mode 100644 article/weather_station_article.html create mode 100644 article/weather_station_article.md create mode 100644 build-doc/weather_station_article.md diff --git a/CHANGELOG.md b/CHANGELOG.md index de355ae..9c9ec41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,3 +51,9 @@ All notable changes to this project will be documented in this file. - Changed some variables to the propper standard (uint8_t, uint16_t, etc.) - SparkFun wind interrupt now calculates over 3 seconds in stead of 1 second (KNMI standard)] + +## [0.2.3] - 2024-02-28 + +### Changed + +- Humidity often got stuck at 100%. Heater algorithm now heats for 10 minutes and cools down for 10 minutes (was 5min/15min) diff --git a/article/Makefile b/article/Makefile new file mode 100644 index 0000000..44d920f --- /dev/null +++ b/article/Makefile @@ -0,0 +1,9 @@ +html: + pandoc -s weather_station_article.md --toc --toc-depth=1 -c ./css/mvp.css \ + --template ./template/template.html -o weather_station_article.html + +pdf: + pandoc weather_station_article.md --toc -o weather_station_article.pdf --pdf-engine=xelatex -H ./template/custom_settings.tex + +clean: + rm -rvf build diff --git a/article/css/mvp.css b/article/css/mvp.css new file mode 100644 index 0000000..94fcb2f --- /dev/null +++ b/article/css/mvp.css @@ -0,0 +1,563 @@ +/* MVP.css v1.14 - https://github.com/andybrewer/mvp */ +/* Edited by Konstapel https://meezenest.nl/mees */ + +:root { + --active-brightness: 0.85; + --border-radius: 5px; + --box-shadow: 2px 2px 10px; + --color-accent: #f4f0ec; + --color-bg: #fff; + --color-bg-secondary: #e9e9e9; + --color-link: #a9a9a9; + --color-secondary: #3366FF; + --color-secondary-accent: #920de90b; + --color-shadow: #f4f4f4; + --color-table: #a9a9a9; + --color-text: #000; + --color-text-secondary: #999; + --font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; + --hover-brightness: 1.2; + --justify-important: center; + --justify-normal: left; + --line-height: 1.5; + --width-card: 285px; + --width-card-medium: 460px; + --width-card-wide: 1080px; + --width-content: 1080px; +} + +@media (prefers-color-scheme: dark) { + :root[color-mode="user"] { + --color-accent: #0097fc4f; + --color-bg: #333; + --color-bg-secondary: #555; + --color-link: #0097fc; + --color-secondary: #e20de9; + --color-secondary-accent: #e20de94f; + --color-shadow: #bbbbbb20; + --color-table: #0097fc; + --color-text: #f7f7f7; + --color-text-secondary: #aaa; + } +} + +html { + scroll-behavior: smooth; +} + +@media (prefers-reduced-motion: reduce) { + html { + scroll-behavior: auto; + } +} + +/* Layout */ +article aside { + background: var(--color-secondary-accent); + border-left: 4px solid var(--color-secondary); + padding: 0.01rem 0.8rem; +} + +body { + background: var(--color-bg); + color: var(--color-text); + font-family: var(--font-family); + line-height: var(--line-height); + margin: 0; + overflow-x: hidden; + padding: 0; + font-size: 110%; +} + +footer, +header, +main { + margin: 0 auto; + max-width: var(--width-content); + padding: 3rem 1rem; +} + +main { + border: 1px solid lightgray; + border-radius: 5px; +} + +footer { + font-size: 0.7em; +} + +hr { + background-color: var(--color-bg-secondary); + border: none; + height: 1px; + margin: 4rem 0; + width: 100%; +} + +section { + display: flex; + flex-wrap: wrap; + justify-content: var(--justify-important); +} + +section img, +article img { + max-width: 100%; +} + +section pre { + overflow: auto; +} + +section aside { + border: 1px solid var(--color-bg-secondary); + border-radius: var(--border-radius); + box-shadow: var(--box-shadow) var(--color-shadow); + margin: 1rem; + padding: 1.25rem; + width: var(--width-card); +} + +section aside:hover { + box-shadow: var(--box-shadow) var(--color-bg-secondary); +} + +[hidden] { + display: none; +} + +/* Headers */ +article header, +div header, +main header { + padding-top: 0; +} + +header { + text-align: var(--justify-important); +} + +header a b, +header a em, +header a i, +header a strong { + margin-left: 0.5rem; + margin-right: 0.5rem; +} + +header nav img { + margin: 1rem 0; +} + +section header { + padding-top: 0; + width: 100%; +} + +/* Nav */ +nav { + align-items: center; + display: flex; + font-weight: bold; + justify-content: space-between; + margin-bottom: 7rem; +} + +nav ul { + list-style: none; + padding: 0; +} + +nav ul li { + display: inline-block; + margin: 0 0.5rem; + position: relative; + text-align: left; +} + +/* Nav Dropdown */ +nav ul li:hover ul { + display: block; +} + +nav ul li ul { + background: var(--color-bg); + border: 1px solid var(--color-bg-secondary); + border-radius: var(--border-radius); + box-shadow: var(--box-shadow) var(--color-shadow); + display: none; + height: auto; + left: -2px; + padding: .5rem 1rem; + position: absolute; + top: 1.7rem; + white-space: nowrap; + width: auto; + z-index: 1; +} + +nav ul li ul::before { + /* fill gap above to make mousing over them easier */ + content: ""; + position: absolute; + left: 0; + right: 0; + top: -0.5rem; + height: 0.5rem; +} + +nav ul li ul li, +nav ul li ul li a { + display: block; +} + +/* Typography */ +code, +samp { + background-color: var(--color-accent); + border-radius: var(--border-radius); + color: var(--color-text); + display: inline-block; + margin: 0 0.1rem; + padding: 0 0.5rem; +} + +details { + margin: 1.3rem 0; +} + +details summary { + font-weight: bold; + cursor: pointer; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + line-height: var(--line-height); +} + +h1 { + font-size: 1.875em; + border-bottom: 1px solid lightgray; +} + +h2 { + font-size: 1.4em; +} + +mark { + padding: 0.1rem; +} + +ol li, +ul li { + padding: 0.2rem 0; +} + +p { + margin: 0.75rem 0; + padding: 0; + width: 100%; +} + +pre { + margin: 1rem 0; + max-width: var(--width-card-wide); + padding: 1rem 0; +} + +pre code, +pre samp { + display: block; + max-width: var(--width-card-wide); + padding: 0.8rem 2rem; + /*white-space: pre-wrap;*/ + overflow-x: auto; +} + +small { + color: var(--color-text-secondary); +} + +sup { + background-color: var(--color-secondary); + border-radius: var(--border-radius); + color: var(--color-bg); + font-size: xx-small; + font-weight: bold; + margin: 0.2rem; + padding: 0.2rem 0.3rem; + position: relative; + top: -2px; +} + +/* Links */ +a { + color: var(--color-link); + display: inline-block; + font-weight: bold; + text-decoration: underline; +} + +a:active { + filter: brightness(var(--active-brightness)); +} + +a:hover { + filter: brightness(var(--hover-brightness)); +} + +a b, +a em, +a i, +a strong, +button, +input[type="submit"] { + border-radius: var(--border-radius); + display: inline-block; + font-size: medium; + font-weight: bold; + line-height: var(--line-height); + margin: 0.5rem 0; + padding: 1rem 2rem; +} + +button, +input[type="submit"] { + font-family: var(--font-family); +} + +button:active, +input[type="submit"]:active { + filter: brightness(var(--active-brightness)); +} + +button:hover, +input[type="submit"]:hover { + cursor: pointer; + filter: brightness(var(--hover-brightness)); +} + +a b, +a strong, +button, +input[type="submit"] { + background-color: var(--color-link); + border: 2px solid var(--color-link); + color: var(--color-bg); +} + +a em, +a i { + border: 2px solid var(--color-link); + border-radius: var(--border-radius); + color: var(--color-link); + display: inline-block; + padding: 1rem 2rem; +} + +article aside a { + color: var(--color-secondary); +} + +/* Images */ +figure { + margin: 0; + padding: 0; + text-align: center; +} + +figure img { + max-width: 100%; + max-height: 500px; +} + +figure figcaption { + color: var(--color-text-secondary); +} + +/* Forms */ +button:disabled, +input:disabled { + background: var(--color-bg-secondary); + border-color: var(--color-bg-secondary); + color: var(--color-text-secondary); + cursor: not-allowed; +} + +button[disabled]:hover, +input[type="submit"][disabled]:hover { + filter: none; +} + +form { + border: 1px solid var(--color-bg-secondary); + border-radius: var(--border-radius); + box-shadow: var(--box-shadow) var(--color-shadow); + display: block; + max-width: var(--width-card-wide); + min-width: var(--width-card); + padding: 1.5rem; + text-align: var(--justify-normal); +} + +form header { + margin: 1.5rem 0; + padding: 1.5rem 0; +} + +input, +label, +select, +textarea { + display: block; + font-size: inherit; + max-width: var(--width-card-wide); +} + +input[type="checkbox"], +input[type="radio"] { + display: inline-block; +} + +input[type="checkbox"]+label, +input[type="radio"]+label { + display: inline-block; + font-weight: normal; + position: relative; + top: 1px; +} + +input[type="range"] { + padding: 0.4rem 0; +} + +input, +select, +textarea { + border: 1px solid var(--color-bg-secondary); + border-radius: var(--border-radius); + margin-bottom: 1rem; + padding: 0.4rem 0.8rem; +} + +input[type="text"], +textarea { + width: calc(100% - 1.6rem); +} + +input[readonly], +textarea[readonly] { + background-color: var(--color-bg-secondary); +} + +label { + font-weight: bold; + margin-bottom: 0.2rem; +} + +/* Popups */ +dialog { + border: 1px solid var(--color-bg-secondary); + border-radius: var(--border-radius); + box-shadow: var(--box-shadow) var(--color-shadow); + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 50%; + z-index: 999; +} + +/* Tables */ +table { + border: 1px solid var(--color-bg-secondary); + border-radius: var(--border-radius); + border-spacing: 0; + display: inline-block; + max-width: 100%; + overflow-x: auto; + padding: 0; + white-space: nowrap; +} + +table td, +table th, +table tr { + padding: 0.4rem 0.8rem; + text-align: var(--justify-important); +} + +table thead { + background-color: var(--color-table); + border-collapse: collapse; + border-radius: var(--border-radius); + /*color: var(--color-bg);*/ + margin: 0; + padding: 0; +} + +table thead th:first-child { + border-top-left-radius: var(--border-radius); +} + +table thead th:last-child { + border-top-right-radius: var(--border-radius); +} + +table thead th:first-child, +table tr td:first-child { + text-align: var(--justify-normal); +} + +table tr:nth-child(even) { + background-color: var(--color-accent); +} + +/* Quotes */ +blockquote { + display: block; + font-size: x-large; + line-height: var(--line-height); + margin: 1rem auto; + max-width: var(--width-card-medium); + padding: 1.5rem 1rem; + text-align: var(--justify-important); +} + +blockquote footer { + color: var(--color-text-secondary); + display: block; + font-size: small; + line-height: var(--line-height); + padding: 1.5rem 0; +} + +/* Scrollbars */ +* { + scrollbar-width: thin; + scrollbar-color: rgb(202, 202, 232) auto; +} + +*::-webkit-scrollbar { + width: 5px; + height: 5px; +} + +*::-webkit-scrollbar-track { + background: transparent; +} + +*::-webkit-scrollbar-thumb { + background-color: rgb(202, 202, 232); + border-radius: 10px; +} + +h1.title { + border-bottom: 0px solid white; +} + diff --git a/article/images/weather_station_schematic.svg b/article/images/weather_station_schematic.svg new file mode 100644 index 0000000..79d9746 --- /dev/null +++ b/article/images/weather_station_schematic.svg @@ -0,0 +1,33282 @@ + + + +SVG Picture created as ds-15901_interface.svg date 2024/01/14 17:15:37 + Picture generated by Eeschema-SVG + + + + + + + + + + + + + +1 +1 + + +2 +2 + +3 +3 + +4 +4 + + +5 +5 + +6 +6 + + + + + + +1 +1 + + +2 +2 + +3 +3 + +4 +4 + + +5 +5 + +6 +6 + + + + +A +A + + +B +B + +C +C + +D +D + + + + +A +A + + +B +B + +C +C + +D +D + +Date: 2023-12-29 +Date: 2023-12-29 + + + + + + + + + + + + + + + + + + + + +KiCad E.D.A. kicad 6.0.11 +KiCad E.D.A. kicad 6.0.11 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Rev: A +Rev: A + + + + + + + + + + +Size: A4 +Size: A4 + + + + + + + + + + + +Id: 1/1 +Id: 1/1 + + + + + + + + + + + + + +Title: DS-15901 weather station interface with RS-485 ModBus +Title: DS-15901 weather station interface with RS-485 ModBus + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +File: ds-15901_interface.kicad_sch +File: ds-15901_interface.kicad_sch + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Sheet: / +Sheet: / + + + + + + + + + + + + +Mees Electronics +Mees Electronics + + + + + + + + + + + + + + + + + + + + + + +M.T. Konstapel +M.T. Konstapel + + + + + + + + + + + + + + + + + + + + +https://meezenest.nl/mees +https://meezenest.nl/mees + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +R18 +R18 + + + + + +2k2 +2k2 + + + + + + + + + + + + + + + + + + + + +1 +1 + + + +2 +2 + + +3 +3 + +J2 +J2 + + +RS-485 +RS-485 + + + + + + + + + + + + + +GND +GND + + + + + + + + + + + + + + + + + + + + +1 +1 + + + +2 +2 + + +3 +3 + + +4 +4 + + +J5 +J5 + + +I2C@5V +I2C@5V + + + + + + + + + + + + + + + + + + + + + +C4 +C4 + + + +1U/10V +1U/10V + + + + + + + + + + + + + + + + + + + +GND + +GND + + + + +1 + +1 + + + +VI +VI + + +2 +2 + + +VO +VO + + +3 +3 + +U4 +U4 + + + +MCP1700-3302E +MCP1700-3302E + + + + + + + + + + + + + + + + + + + + + + ++5V ++5V + + + + + + + + + + + + + + + + + + +C7 +C7 + + +1U/10V +1U/10V + + + + + + + + + + + + + + + + + + + + + + +GND +GND + + + + + + + + + + + + + + +R19 +R19 + + + + + +2k2 +2k2 + + + + + + + + + + +GND +GND + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 +1 + + + + +2 + +2 + + +3 +3 + +Q2 +Q2 + + + +2N7000 +2N7000 + + + + + + + + + + + + + + + + + +R5 +R5 + + + +820R +820R + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 +1 + + + + +2 + +2 + + +3 +3 + +Q1 +Q1 + + + + +2N7000 +2N7000 + + + + + + + + + + + + + ++5V ++5V + + + + + + + + + + + ++5V ++5V + + + + + + + + + + + ++5V ++5V + + + + + + + + + +GND +GND + + + + + + + + + + + + + + + + + + + + +1 +1 + + + +2 +2 + + +3 +3 + + +4 +4 + + + +5 +5 + + +6 +6 + +J3 +J3 + + +RJ12 +RJ12 + + + + + + + + + + + + + ++5V ++5V + + + + + + + + + +GND +GND + + + + + + + + + + + + + + + + + +C8 +C8 + + +10p +10p + + + + + + + + + + + + ++5V ++5V + + + + + + + + + + + + + + + +R3 +R3 + + + +100k +100k + + + + + + + + + + + + + + + + + + + + + + + + + + +1 +1 + + + +2 +2 + + +3 +3 + + +4 +4 + + + +5 +5 + + +6 +6 + +J9 +J9 + + +ADDRESS +ADDRESS + + + + + + + + + + + + + + + + + + + + + + + +D2 +D2 + + +TVS_15V +TVS_15V + + + + + + + + + + + + + + + + + + + + + + + +C10 +C10 + + + + +100n +100n + + + + + + + + + + + + + + + + +Vin +Vin + + + + + +1 +1 + + + + +GND + +GND + + + + +2 + +2 + + +Vout +Vout + + + + + + +3 +3 + +U3 +U3 + + +TSR_1-2450 +TSR_1-2450 + + + + + + + + + + + + + + + + + + + +GND +GND + + + + + + + + + + + + + + + + +D3 +D3 + + +10V +10V + + + + + + + + + + + + + + + + + + +C3 +C3 + + +100U/50V +100U/50V + + + + + + + + + + + + + + + + + + + + + + + +C6 +C6 + + +15n +15n + + + + + + + + + + + + + + + + + + +1 +1 + + + +2 +2 + +J1 +J1 + + + +13.8V INPUT +13.8V INPUT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + +1 + + + +2 +2 + + +3 +3 + +Q3 +Q3 + + + +IRF9540 +IRF9540 + + + + + + + + + + + + + + + + + + + + + +R1 +R1 + + + + +12k +12k + + + + + + + + + + + + + + + + + + + +1 +1 + + + +2 +2 + +J4 +J4 + + + +13.8V OUTPUT +13.8V OUTPUT + + + + + + + + + + + + + + + + + + + + + ++12V ++12V + + + + + + + + + + + + + + + + + + + + +C1 +C1 + + + +150n +150n + + + + + + + + + + + + + ++3V3 ++3V3 + + + + + + + + + + + + + + + + + + +D1 +D1 + + + +TVS_24V +TVS_24V + + + + + + + + + + + + + + + + + + + + + + + +C5 +C5 + + +150n +150n + + + + + + + + + + + + + ++5V ++5V + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +RO +RO + + + +1 +1 + + + +~{RE} +~{RE} + + + + + + +2 +2 + + +DE +DE + + + +3 +3 + + +DI +DI + + +4 +4 + + + + +GND + +GND + + + + +5 + +5 + + +A +A + + +6 +6 + + +B +B + +7 +7 + + + +VCC + +VCC + + + + +8 + +8 + +U1 +U1 + + + +MAX487E +MAX487E + + + + + + + + + + + + + + + + + + + + + + +R8 +R8 + + + +10R +10R + + + + + + + + + + + + + + + + + + +1 +1 + + + +2 +2 + +J7 +J7 + + +Termination +Termination + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +R14 +R14 + + + + + + +120R +120R + + + + + + + + + + + + + + + + + +R9 +R9 + + + +10R +10R + + + + + + + + + + +GND +GND + + + + + + + + + + + + + + + + + +C2 +C2 + + +100n +100n + + + + + + + + + + + +GND +GND + + + + + + + + +GND +GND + + + + + + + + + + + + + + +R4 +R4 + + + + +10k +10k + + + + + + + + + + + + + ++5V ++5V + + + + + + + + + + + ++5V ++5V + + + + + + + + + + + ++3V3 ++3V3 + + + + + + + + + + + + + + + + + + + + + + +1 +1 + + + +2 +2 + + +3 +3 + + +4 +4 + + +J8 +J8 + + +I2C@3V3 +I2C@3V3 + + + + + + + + + + + + + +GND +GND + + + + + + + + + + + + +H1 +H1 + + + + + +MountingHole +MountingHole + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +H2 +H2 + + + + +MountingHole +MountingHole + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 +1 + + + +2 +2 + + +3 +3 + + +4 +4 + + + +5 +5 + + +6 +6 + +J6 +J6 + + +RJ12 +RJ12 + + + + + + + + + + + + + + + + + +R2 +R2 + + + +10k +10k + + + + + + + + + + + + + + + +H3 +H3 + + + + +MountingHole +MountingHole + + + + + + + + + + + + + + + + + + + + + + + + + + + ++3V3 ++3V3 + + + + + + + + + + + + + + + + +GND + +GND + + + + +1 + +1 + + + +CSB +CSB + + + +2 +2 + + +SDI +SDI + + + +3 +3 + + +SCK +SCK + + + + + +4 +4 + + + +SDO +SDO + + + +5 +5 + + + +VDDIO + +VDDIO + + + + + + +6 + +6 + + + +GND + +GND + + + + +7 + +7 + + + +VDD + +VDD + + + + +8 + +8 + +U? +U? + + + +BMP280 +BMP280 + + + + + + + + + + + + + + + +H4 +H4 + + + + + +MountingHole +MountingHole + + + + + + + + + + + + + + + + + + + + + + + + + + +IO10 +IO10 + + + + + +1 +1 + + + +RESET +RESET + + + + + + + + + +10 +10 + + + + + +GND + +GND + + + + +11 + +11 + + + + + + ++9V + ++9V + + + + + +12 + +12 + + + + +TX +TX + + + + +13 +13 + + + + +RX +RX + + + + +14 +14 + + + + + +RESET +RESET + + + + + + + + + +15 +15 + + + + + +GND + +GND + + + + +16 + +16 + + + + +IO2 +IO2 + + + +17 +17 + + + + +IO3 +IO3 + + + +18 +18 + + + + +IO4 +IO4 + + + + +19 +19 + + + + +IO11 +IO11 + + + + + + +2 +2 + + +IO5 +IO5 + + + +20 +20 + + + +IO6 +IO6 + + + +21 +21 + + + + +IO7 +IO7 + + + +22 +22 + + + +IO8 +IO8 + + + +23 +23 + + + +IO9 +IO9 + + + +24 +24 + + + + +SDA +SDA + + + + +25 +25 + + + +SCL +SCL + + + +26 +26 + + + +IO12 +IO12 + + + + + +3 +3 + + +IO13 +IO13 + + + + + +4 +4 + + + +ADC0 +ADC0 + + + + + +5 +5 + + +ADC1 +ADC1 + + + + + + +6 +6 + + +ADC2 +ADC2 + + + + + +7 +7 + + +ADC3 +ADC3 + + + + + +8 +8 + + + ++5V + ++5V + + + + + +9 + +9 + +U2 +U2 + + +Arduino Pro Mini +Arduino Pro Mini + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +R23 +R23 + + + + +2k2 +2k2 + + + + + + + + + + +GND +GND + + + + + + + + + + ++3V3 ++3V3 + + + + + + + + + + + + + + + + +R22 +R22 + + + + +2k2 +2k2 + + + + + + + + + + +SDA +SDA + + + + + + + + + +SCL +SCL + + + + + + + + +DE +DE + + + + + + + + +TX +TX + + + + + + + + + +RX +RX + + + + + + + + + +SDA +SDA + + + + + + + + + +DE +DE + + + + + + + + +RX +RX + + + + + + + + + +TX +TX + + + + + + + + + +SCL +SCL + + + + + + + + +Annotations in brackets are the annotiations of +Annotations in brackets are the annotiations of + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +the "aprs_measurement_node" pcb. +the "aprs_measurement_node" pcb. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +(J9 pin 3, 4, 5 and 6) + +(J9 pin 3, 4, 5 and 6) + + + + + + + + + + + + + + + + + + + + + + + + + + + +Convert "aprs_measurement_node" pcd: +Convert "aprs_measurement_node" pcd: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +- Remove RV1, RV2, R3, R6, R7, R10, C11 and C12 +- Remove RV1, RV2, R3, R6, R7, R10, C11 and C12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +- Replace C8 and C9 with jumper +- Replace C8 and C9 with jumper + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +- Change R2 and R4 to 10k +- Change R2 and R4 to 10k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +- Place 100k resistor between pin 1 and 2 of J9 +- Place 100k resistor between pin 1 and 2 of J9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +- Place 10pF capacitor between pin 2 and 6 of J9 +- Place 10pF capacitor between pin 2 and 6 of J9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +- Place I2C level converter +- Place I2C level converter + + + + + + + + + + + + + + + + + + + + + + + + + + + + +- Place U4, C4 and C7 +- Place U4, C4 and C7 + + + + + + + + + + + + + + + + + + + + + + +- Connect U2 pin 18 to U4 pin 24 +- Connect U2 pin 18 to U4 pin 24 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +- Connect U2 pin 17 to U4 pin 6 +- Connect U2 pin 17 to U4 pin 6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +- Short U4 pin 2 and U4 pin 3 +- Short U4 pin 2 and U4 pin 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +The ModBus address can be selected by connecting +The ModBus address can be selected by connecting + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +pin 3, 4 and/or 5 of J9 to pin 6 (ground). +pin 3, 4 and/or 5 of J9 to pin 6 (ground). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +RS-485 transceiver +RS-485 transceiver + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +R5 protects the circuit when the +R5 protects the circuit when the + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Arduino Pro Mini is being programmed +Arduino Pro Mini is being programmed + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +via the serial port. +via the serial port. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +The 120R terminator resistor +The 120R terminator resistor + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +is only needed if this node is +is only needed if this node is + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +at the beginning or end of +at the beginning or end of + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +the RS485 line. +the RS485 line. + + + + + + + + + + + + + + + + + + + + + + + +Rain +Rain + + + + + + + + + + + + +ESD and reverse polarity protection +ESD and reverse polarity protection + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +NOTE: +NOTE: + + + + + + + + +only IO2 and IO3 of Arduino Pro Mini +only IO2 and IO3 of Arduino Pro Mini + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +can be used as interrupt inputs. +can be used as interrupt inputs. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Power supply +Power supply + + + + + + + + + + + + + + + + + + + + +Wind speed +Wind speed + + + + + + + + + + + + + + + + + + +I2C is used for communication +I2C is used for communication + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +with temperature, humidity and +with temperature, humidity and + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +pressure sensors. +pressure sensors. + + + + + + + + + + + + + + + + + + + + + + + + + + +I2C level shifter +I2C level shifter + + + + + + + + + + + + + + + + + + + + + + + + +(J3 and J6) +(J3 and J6) + + + + + + + + + + + + + + + + +Microcontroller +Microcontroller + + + + + + + + + + + + + + + + + + + + + + + + + +Wind direction +Wind direction + + + + + + + + + + + + + + + + + + + + + + + + + + +(J9 pin 1 and 6) +(J9 pin 1 and 6) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +GND +GND + + + +Q1 +Q1 + + + + +2N7000 +2N7000 + + + + + + + +1 +1 + + + + +2 + +2 + + +3 +3 + +R18 +R18 + + + + + +2k2 +2k2 + + + + + + + +Q2 +Q2 + + + +2N7000 +2N7000 + + + + + + + +1 +1 + + + + +2 + +2 + + +3 +3 + +R19 +R19 + + + + + +2k2 +2k2 + + + + + + + +U4 +U4 + + + +MCP1700-3302E +MCP1700-3302E + + + + + + + + + + + + + + + + + +GND + +GND + + + + +1 + +1 + + + +VI +VI + + +2 +2 + + +VO +VO + + +3 +3 + +C4 +C4 + + + +1U/10V +1U/10V + + + + + + + + + + +C2 +C2 + + +100n +100n + + + + + + + + +GND +GND + + + +C10 +C10 + + + + +100n +100n + + + + + + + + +U3 +U3 + + +TSR_1-2450 +TSR_1-2450 + + + + + + + + + + + + + + + +Vin +Vin + + + + + +1 +1 + + + + +GND + +GND + + + + +2 + +2 + + +Vout +Vout + + + + + + +3 +3 + +Q3 +Q3 + + + +IRF9540 +IRF9540 + + + + + + + + + + + + +1 + +1 + + + +2 +2 + + +3 +3 + +D1 +D1 + + + +TVS_24V +TVS_24V + + + + + + + + + + + +GND +GND + + + +C8 +C8 + + +10p +10p + + + + + + + +J9 +J9 + + +ADDRESS +ADDRESS + + + + + + + + + + + +1 +1 + + + +2 +2 + + +3 +3 + + +4 +4 + + + +5 +5 + + +6 +6 + +U2 +U2 + + +Arduino Pro Mini +Arduino Pro Mini + + + + + + + + + + + + + + + + + + + + + + + + + +IO10 +IO10 + + + + + +1 +1 + + + +RESET +RESET + + + + + + + + + +10 +10 + + + + + +GND + +GND + + + + +11 + +11 + + + + + + ++9V + ++9V + + + + + +12 + +12 + + + + +TX +TX + + + + +13 +13 + + + + +RX +RX + + + + +14 +14 + + + + + +RESET +RESET + + + + + + + + + +15 +15 + + + + + +GND + +GND + + + + +16 + +16 + + + + +IO2 +IO2 + + + +17 +17 + + + + +IO3 +IO3 + + + +18 +18 + + + + +IO4 +IO4 + + + + +19 +19 + + + + +IO11 +IO11 + + + + + + +2 +2 + + +IO5 +IO5 + + + +20 +20 + + + +IO6 +IO6 + + + +21 +21 + + + + +IO7 +IO7 + + + +22 +22 + + + +IO8 +IO8 + + + +23 +23 + + + +IO9 +IO9 + + + +24 +24 + + + + +SDA +SDA + + + + +25 +25 + + + +SCL +SCL + + + +26 +26 + + + +IO12 +IO12 + + + + + +3 +3 + + +IO13 +IO13 + + + + + +4 +4 + + + +ADC0 +ADC0 + + + + + +5 +5 + + +ADC1 +ADC1 + + + + + + +6 +6 + + +ADC2 +ADC2 + + + + + +7 +7 + + +ADC3 +ADC3 + + + + + +8 +8 + + + ++5V + ++5V + + + + + +9 + +9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/article/template/custom_settings.tex b/article/template/custom_settings.tex new file mode 100644 index 0000000..96f9757 --- /dev/null +++ b/article/template/custom_settings.tex @@ -0,0 +1,16 @@ +% Override default figure placement To be within the flow of the text rather +% than on it's own page. +\usepackage{float} +\usepackage{graphicx} +\makeatletter +\def\fps@figure{H} +\makeatother + +% Scale all large images to 50% of twext width +\makeatletter +\setkeys{Gin}{width=\ifdim\Gin@nat@width>\linewidth + 0.5\linewidth +\else + \Gin@nat@width +\fi} +\makeatother diff --git a/article/template/template.html b/article/template/template.html new file mode 100644 index 0000000..e697449 --- /dev/null +++ b/article/template/template.html @@ -0,0 +1,120 @@ + + + + + + +$for(author-meta)$ + +$endfor$ +$if(date-meta)$ + +$endif$ +$if(keywords)$ + +$endif$ + $if(title-prefix)$$title-prefix$ – $endif$$pagetitle$ +$if(highlighting-css)$ + +$endif$ +$for(css)$ + +$endfor$ + +$if(math)$ + $math$ +$endif$ +$for(header-includes)$ + $header-includes$ +$endfor$ + + +$for(include-before)$ +$include-before$ +$endfor$ +$if(title)$ +
+ +

$title$

+$if(subtitle)$ +

$subtitle$

+$endif$ +$for(author)$ +

$author$

+$endfor$ +$if(date)$ +

$date$

+$endif$ +$if(pdf_version)$ +

PDF version

+$endif$ +
+$endif$ +
+
+$if(abstract)$ +

Abstract $abstract$

+$endif$ +$body$ +$for(include-after)$ +$include-after$ +$endfor$ +
+
+
+ + + diff --git a/article/weather_station_article.html b/article/weather_station_article.html new file mode 100644 index 0000000..99cbd25 --- /dev/null +++ b/article/weather_station_article.html @@ -0,0 +1,205 @@ + + + + + + + + + APRS weerstation + + + + +
+ +

APRS weerstation

+

met hamnet verbinding

+

M.T. Konstapel

+

2024-02-03

+

PDF version

+
+
+
+

Abstract

Ik maak veel gebruik van het APRS netwerk: +positiebepaling, telemetry en berichten versturen; ik doe het allemaal. +Dit kan omdat ik dicht bij de Duitse grens woon: anders dan in Nederland +waar het APRS netwerk dankzij lastige regelgeving nagenoeg is verdwenen, +is in Duitsland het netwerk nog springlevend. Ik maak gebruik van Duitse +digipeaters en iGates, die gewoon berichten vanaf het internet mogen +doorzenden. Wat een geluk! Het enige wat ik nog niet kon, was +weergegevens delen via het netwerk. Om daar verandering in te brengen +heb ik een weerstation ontworpen dat elke 10 minuten een weerbericht kan +uitzenden via het APRS netwerk. En omdat het systeem zo’n 100 meter van +mijn huis in de acchtertuin staat, heb ik er ook een 5 GHz hamnet +verbinding naar toe gemaakt, zodat ik het systeem op afstand kan +bedienen. Het hamnet gebruik ik ook om de weermetingen naar mijn Grafana +dashboard te sturen. Oh, en omdat twee beter is dan een heb ik er ook +een 20KB/s hamnet link over 70cm LoRa als backup in geknutseld.

+

Weerstation

+

Als uitgangspunt van het weerstation gebruik ik de SparkFun Weather +Meter. Dit is een kit met drie sensors: een windvaan, een anemometer en +een regenmeter. Deze kit heb ik aangevuld met sensors voor temperatuur, +luchtdruk en luctvochtigheid. Al deze sensors zijn rechtstreeks +aangesloten op een Arduino Mini Pro. Ik heb daar een RS-485 driverchip +en een ompoolbeveiliging aan toegevoegd. Het uiteindelijke schema is +hieronder te zien. Ingewikkeld is de hardware niet, want alle +fuctionaliteit zit in de software.

+
+ + +
+

Het weerstation is uit te lezen via een ModBus interface. Dit is een +industriestandaard, dus er zijn legio mogelijkheden om met het +weerstation te communiceren. De ModBus registers bevatten de meetwaarden +van de sensors en worden elke twee seconde ververst. Dit bepaald dus de +maximale uitleesfrequentie. De volgende gegevens zijn beschikbaar:

+
    +
  • Windrichting in graden
  • +
  • Gemiddelde wind snelheid van de laatste 10 minuten in m/s
  • +
  • Maximale windstoot van de laatste 10 minuten in m/s
  • +
  • Hoeveelheid regen in het afgelopen uur in mm
  • +
  • Hoeveelheid regen in de afgelopen 24 uur in mm
  • +
  • Temperatuur in graden C
  • +
  • Luchtvochtigheid in %
  • +
  • Luchtdruk in hPa
  • +
+

Daarnaast zijn er nog een aantal statusregisters beschikbaar. Deze +worden besproken in de uitgebreide bouwbeschrijving die beschikbaar is +op mijn website.

+

De luchtvochtigheidssensor kan bij een hoge luchtvochtigheid +verzadigd raken en zo blijven steken op 100%. Om dit te voorkomen is het +mogelijk om de sensor automatisch te laten verwarmen wanneer de +luchtvochtigheid langer dan een uur boven de 96% is. De verwarming wordt +dan elke 20 minuten voor 5 minuten aangezet. In de 15 minuten die +overblijven koelt de sensor weer af tot de omgevingstemperatuur. Dit +proces wordt heraald totdat de sensor weer een waarde beneden de 96% +aangeeft. Tijdens het opwarmen en afkoelen kan de luchtvochtigheid en +temperatuur maar eens in de 20 minuten worden gemeten. Dit is de prijs +die betaald moet worden wanneer we een goedkope luchtvochtigheidssensor +gebruiken.

+

APRS

+

Om de weermetingen te kunnen uitzenden via het APRS netwerk is er een +2 meter FM zender (een oude Alinco portofoon) en een 1200baud modem (een +variant op het MicroModem van markqvist) nodig. En een computer om de +gegevens via de ModBus uit het weerstation te lezen en door te sturen +naar het modem. Een Raspberry Pi Zero 2W is daar perfect geschikt voor. +Deze is goedkoop, klein en verbruikt weinig energie. Omdat een APRS +weerstation ook zijn positie en tijd moet doorgeven om op de kaart gezet +te kunnen worden is er een GPS module via USB aangesloten op de +Raspberry Pi. Strikt genomen is de tijd niet noodzakelijk en omdat het +station vast is opgesteld kan de positie ook handmatig worden ingesteld, +maar een gps module voegt weer extra complexiteit toe en dat maakt het +project net weer wat interessanter. Een eenvoudig Python programma leest +het weerstation uit, vraagt de positie en de tijd van de gps ontvanger +op en construeerd het APRS frame dat uitgezonden moet worden. Dit frame +wordt vervolgens via de Linux AX.25 stack naar het modem gestuurd.

+

Omdat APRS over LoRa op de 70cm band steeds poulairder wordt heb ik +ook een LoRa module op de Raspberry Pi aangeloten. Het weerbericht kan +zo ook via LoRa worden uitgezonden. De software hiervoor is een in +Python geschreven KISS interface. Via deze software kan de LoRa module +gekoppeld worden aan de AX.25 stack. De Raspberry Pi ziet het modem als +elk ander KISS compatible modem.

+

Met een diplexer worden de signalen van beide zenders samengevoegd en +gaan zo naar een dualband antene.

+

HamNet

+

Het syteem kan autonoom werken, maar het is handig (en noodzakelijk) +om het systeem van afstand te kunnen bedienen en wanneer dat nodig is +ook uit te kunnen schakelen. Daarvoor heb ik een 5GHz HamLink tussen het +huis en het weerstation aangelegt. Op deze manier heb ik een snelle +netwerkverbinding naar de Raspberry Pi en kan ik via telnet inloggen en +het systeem bedienen. De verbindig wordt ook gebruikt om verbindig te +maken met het APRS-IS netwerk op het internet. Zo doet mijn weerstation +ook dienst als RX-only iGate voor zowel traditioneel APRS als LoRa APRS. +De HamNet link maakt gebruik van commercieel verkrijgbare schotels. Ik +gebruik apparatuur van Unifi Ubiquiti, maar apparatuur van Mikrotik is +even goed geschikt.

+

De snelle netwerkverbinding is handig, maar wanneer het systeem +autonoom werkt is het wel een beetje een overkill, want de verbinding +wordt dan enkel gebruikt om APRS berichten door te sturen naar het +APRS-IS netwerk. Daarom heb ik ook nog een lage snelheid +netwerkverbinding geintegreerd. Deze heeft een doorvoersnelheid van iets +meer dan 20KB/s, wat genoeg is voor de toepassing. Het is zelfs mogelijk +om via deze langzame verbinding in te loggen via telnet. Dat gaat dan +wat trager, maar als backup is het prima geschikt. Zo heb ik twee +manieren om het systeem van afstand te beheren. De verbinding gaat over +LoRa via de 70cm band. Hiervoor gebruik ik een kant en klaar board, een +LilyGO TTGO T3 LoRa32 433MHz V1.6.1 ESP32. Hierop heb ik de Rnode +firmware van unsigned.io gezet. Met de bijbehorende Linux software +(tncattach) wordt dit een netwerkinterface onder Linux waarover ik het +netwerkverkeer kan leiden.

+

Meer informatie

+

Dit artikel is slechts een introductie van het APRS weerstation. Meer +informatie is te vinden op mijn website https://meezenest.nl/mees Daar +vind je uitgebreide documentatie en alle ontwerpbestanden en broncode +die je nodig hebt om zelf aan deslag te gaan.

+

Verantwoording

+

Bouwbeschrijving +weerstation: +https://www.meezenest.nl/mees-elektronica/projects/weather_station/build_doc/weather_station.html

+

1200bd +modem: +https://www.meezenest.nl/mees-elektronica/packetmodem_nano.html

+

LoRa KISS +software: https://git.meezenest.nl/marcel/RPi-LoRa-KISS-TNC

+

Raspberry +Pi met LoRa module: +https://www.meezenest.nl/mees-elektronica/RPi_LoRa_shield.html

+

Copyright (C) 2023, 2024 M.T. Konstapel - PE1RXF

+

https://meezenest.nl/mees/

+

This work is licensed under a Creative Commons Attribution-ShareAlike +4.0 International License.

+
+
+
+ + + diff --git a/article/weather_station_article.md b/article/weather_station_article.md new file mode 100644 index 0000000..37c342e --- /dev/null +++ b/article/weather_station_article.md @@ -0,0 +1,71 @@ +--- +title: APRS weerstation +subtitle: met hamnet verbinding +author: M.T. Konstapel +date: 2024-02-03 +website: https://meezenest.nl/mees/ +page_back: https://meezenest.nl/mees/weather_station.html +logo: ./images/mees_logo.svg +pdf_version: ./weather_station_article.pdf +git_repo: https://git.meezenest.nl/marcel/weather_station +numbersections: true +# Formatting: +geometry: "a4paper, left=2.0cm, right=2.0cm, top=1.9cm, bottom=2.54cm" +abstract: > + Ik maak veel gebruik van het APRS netwerk: positiebepaling, telemetry en berichten versturen; ik doe het allemaal. Dit kan omdat ik dicht bij de Duitse grens woon: anders dan in Nederland waar het APRS netwerk dankzij lastige regelgeving nagenoeg is verdwenen, is in Duitsland het netwerk nog springlevend. Ik maak gebruik van Duitse digipeaters en iGates, die gewoon berichten vanaf het internet mogen doorzenden. Wat een geluk! Het enige wat ik nog niet kon, was weergegevens delen via het netwerk. Om daar verandering in te brengen heb ik een weerstation ontworpen dat elke 10 minuten een weerbericht kan uitzenden via het APRS netwerk. En omdat het systeem zo'n 100 meter van mijn huis in de acchtertuin staat, heb ik er ook een 5 GHz hamnet verbinding naar toe gemaakt, zodat ik het systeem op afstand kan bedienen. Het hamnet gebruik ik ook om de weermetingen naar mijn Grafana dashboard te sturen. Oh, en omdat twee beter is dan een heb ik er ook een 20KB/s hamnet link over 70cm LoRa als backup in geknutseld. +--- + +# Weerstation + +Als uitgangspunt van het weerstation gebruik ik de SparkFun Weather Meter. Dit is een kit met drie sensors: een windvaan, een anemometer en een regenmeter. Deze kit heb ik aangevuld met sensors voor temperatuur, luchtdruk en luctvochtigheid. Al deze sensors zijn rechtstreeks aangesloten op een Arduino Mini Pro. Ik heb daar een RS-485 driverchip en een ompoolbeveiliging aan toegevoegd. Het uiteindelijke schema is hieronder te zien. Ingewikkeld is de hardware niet, want alle fuctionaliteit zit in de software. + +![Schema](./images/weather_station_schematic.svg "Schema") + +Het weerstation is uit te lezen via een ModBus interface. Dit is een industriestandaard, dus er zijn legio mogelijkheden om met het weerstation te communiceren. De ModBus registers bevatten de meetwaarden van de sensors en worden elke twee seconde ververst. Dit bepaald dus de maximale uitleesfrequentie. De volgende gegevens zijn beschikbaar: + +- Windrichting in graden +- Gemiddelde wind snelheid van de laatste 10 minuten in m/s +- Maximale windstoot van de laatste 10 minuten in m/s +- Hoeveelheid regen in het afgelopen uur in mm +- Hoeveelheid regen in de afgelopen 24 uur in mm +- Temperatuur in graden C +- Luchtvochtigheid in % +- Luchtdruk in hPa + +Daarnaast zijn er nog een aantal statusregisters beschikbaar. Deze worden besproken in de uitgebreide bouwbeschrijving die beschikbaar is op mijn website. + +De luchtvochtigheidssensor kan bij een hoge luchtvochtigheid verzadigd raken en zo blijven steken op 100%. Om dit te voorkomen is het mogelijk om de sensor automatisch te laten verwarmen wanneer de luchtvochtigheid langer dan een uur boven de 96% is. De verwarming wordt dan elke 20 minuten voor 5 minuten aangezet. In de 15 minuten die overblijven koelt de sensor weer af tot de omgevingstemperatuur. Dit proces wordt heraald totdat de sensor weer een waarde beneden de 96% aangeeft. Tijdens het opwarmen en afkoelen kan de luchtvochtigheid en temperatuur maar eens in de 20 minuten worden gemeten. Dit is de prijs die betaald moet worden wanneer we een goedkope luchtvochtigheidssensor gebruiken. + +# APRS + +Om de weermetingen te kunnen uitzenden via het APRS netwerk is er een 2 meter FM zender (een oude Alinco portofoon) en een 1200baud modem (een variant op het MicroModem van markqvist) nodig. En een computer om de gegevens via de ModBus uit het weerstation te lezen en door te sturen naar het modem. Een Raspberry Pi Zero 2W is daar perfect geschikt voor. Deze is goedkoop, klein en verbruikt weinig energie. Omdat een APRS weerstation ook zijn positie en tijd moet doorgeven om op de kaart gezet te kunnen worden is er een GPS module via USB aangesloten op de Raspberry Pi. Strikt genomen is de tijd niet noodzakelijk en omdat het station vast is opgesteld kan de positie ook handmatig worden ingesteld, maar een gps module voegt weer extra complexiteit toe en dat maakt het project net weer wat interessanter. Een eenvoudig Python programma leest het weerstation uit, vraagt de positie en de tijd van de gps ontvanger op en construeerd het APRS frame dat uitgezonden moet worden. Dit frame wordt vervolgens via de Linux AX.25 stack naar het modem gestuurd. + +Omdat APRS over LoRa op de 70cm band steeds poulairder wordt heb ik ook een LoRa module op de Raspberry Pi aangeloten. Het weerbericht kan zo ook via LoRa worden uitgezonden. De software hiervoor is een in Python geschreven KISS interface. Via deze software kan de LoRa module gekoppeld worden aan de AX.25 stack. De Raspberry Pi ziet het modem als elk ander KISS compatible modem. + +Met een diplexer worden de signalen van beide zenders samengevoegd en gaan zo naar een dualband antene. + +# HamNet + +Het syteem kan autonoom werken, maar het is handig (en noodzakelijk) om het systeem van afstand te kunnen bedienen en wanneer dat nodig is ook uit te kunnen schakelen. Daarvoor heb ik een 5GHz HamLink tussen het huis en het weerstation aangelegt. Op deze manier heb ik een snelle netwerkverbinding naar de Raspberry Pi en kan ik via telnet inloggen en het systeem bedienen. De verbindig wordt ook gebruikt om verbindig te maken met het APRS-IS netwerk op het internet. Zo doet mijn weerstation ook dienst als RX-only iGate voor zowel traditioneel APRS als LoRa APRS. De HamNet link maakt gebruik van commercieel verkrijgbare schotels. Ik gebruik apparatuur van Unifi Ubiquiti, maar apparatuur van Mikrotik is even goed geschikt. + +De snelle netwerkverbinding is handig, maar wanneer het systeem autonoom werkt is het wel een beetje een overkill, want de verbinding wordt dan enkel gebruikt om APRS berichten door te sturen naar het APRS-IS netwerk. Daarom heb ik ook nog een lage snelheid netwerkverbinding geintegreerd. Deze heeft een doorvoersnelheid van iets meer dan 20KB/s, wat genoeg is voor de toepassing. Het is zelfs mogelijk om via deze langzame verbinding in te loggen via telnet. Dat gaat dan wat trager, maar als backup is het prima geschikt. Zo heb ik twee manieren om het systeem van afstand te beheren. De verbinding gaat over LoRa via de 70cm band. Hiervoor gebruik ik een kant en klaar board, een LilyGO TTGO T3 LoRa32 433MHz V1.6.1 ESP32. Hierop heb ik de Rnode firmware van unsigned.io gezet. Met de bijbehorende Linux software (tncattach) wordt dit een netwerkinterface onder Linux waarover ik het netwerkverkeer kan leiden. + +# Meer informatie + +Dit artikel is slechts een introductie van het APRS weerstation. Meer informatie is te vinden op mijn website https://meezenest.nl/mees Daar vind je uitgebreide documentatie en alle ontwerpbestanden en broncode die je nodig hebt om zelf aan de slag te gaan. + +# Verantwoording + +[Bouwbeschrijving weerstation: https://www.meezenest.nl/mees-elektronica/projects/weather_station/build_doc/weather_station.html](https://www.meezenest.nl/mees-elektronica/projects/weather_station/build_doc/weather_station.html) + +[1200bd modem: https://www.meezenest.nl/mees-elektronica/packetmodem_nano.html](https://www.meezenest.nl/mees-elektronica/packetmodem_nano.html) + +[LoRa KISS software: https://git.meezenest.nl/marcel/RPi-LoRa-KISS-TNC](https://git.meezenest.nl/marcel/RPi-LoRa-KISS-TNC) + +[Raspberry Pi met LoRa module: https://www.meezenest.nl/mees-elektronica/RPi_LoRa_shield.html](https://www.meezenest.nl/mees-elektronica/RPi_LoRa_shield.html) + +Copyright (C) 2023, 2024 M.T. Konstapel - PE1RXF + +[https://meezenest.nl/mees/](https://meezenest.nl/mees/) + +This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License. diff --git a/build-doc/weather_station.html b/build-doc/weather_station.html index e29cd08..ec1f6d8 100644 --- a/build-doc/weather_station.html +++ b/build-doc/weather_station.html @@ -609,7 +609,7 @@ import minimalmodbus instrument = minimalmodbus.Instrument('/dev/ttyUSB1', 14) # register number, number of decimals, function code -wind_direction = instrument.read_register(1, 0, 4) +wind_direction = instrument.read_register(1, 1, 4) print(wind_direction) # register address, value, function code @@ -791,10 +791,12 @@ Zero 2W running the aprx digipeater software, as well as some specially written Python programs to interface the build in LoRa transceiver, the GPS module and the weather station itself. Every 10 minutes the digipeater will read the weather station’s registers and sends the data -as PE1RXF telemetry messages over the APRS network to a server, which -presents the data in a Grafana dashboard. The digipeater can also send -standardized APRS weather reports over the APRS network. But more about -this project can be found here: https://www.meezenest.nl/mees-elektronica/projects/aprs_telemetry/APRS_protocol_nodes_PE1RXF.pdf) +over the APRS network to a server, which presents the data in a Grafana +dashboard. The digipeater can also send standardized APRS weather +reports over the APRS network. But more about this project can be found +here: https://www.meezenest.nl/mees-elektronica/RPi_LoRa_shield.html

$N9xZrzVwf+*_i5KO8Vf#^UfR8iu?}QMpT(*}NjQ{khlS)J{Slc^g_pd$2ir>HA z7a9aI_^O=u8G_OeIN5EbzviD00H5Bw{ClHrpB`UVj~A^R(jB(>-;SSKbDH(yVCD2Z z*3wrmUz=0`n&q?4$L1pCPJ|0qYLg}T9|kn-G#LNhIQt4U{!x~2rN8c6d~CvnJ)!M9 zPzh`0oJ4k|bFTtc(5H(&`A?!N$B~X*gE{2(weq7aa4cGsQ>Ef8QV1t=3Ik zP}QtXcbIN=v!uAE3;vmw#^j)6%hVzEL+>%tp#lJc)u^5v3Q{_4;t>lRtAmEPNato>v>>F$-GDnT6?~Pe9pk?JVlp- zo@@;Z=mAnCfDdad3n*u4cPln%&99XFWa#{j;F`aRpSlXF2%BWWk8ww~YxHAy8_$B3 zw`ZCT#$vgbdz4_0rfkAmx#3n|-I?$?(o6eNX{_0;5^U;y&#^~g^=s&KKm3;tGU5AS z!zh7U1uKQGVP9@8r_TA{(5hJ3jWqNHMVlB40PUUuFA8Bb^mZs0bMxak z;3^I@GiEhmBZ#^QrKUneSu_UTKObsqF?Tx{sr()j>Pn-UuLo`I3Ne&VTjVmKzG&?P zQIp&&3x`jPJ(38HR~^6iMHnsd+GwFiG9Vn|XPvi7}qaOqgPvNy8+Es7*h^vyyR!o|LeSH$oI0*5ln} z??Lx!-iVDtu1c?8Ar3HCdOSbsP@gLaJNm<9WkPD=hAVq4G)Szg;&aZh}EdC#0s zy^n8T*kh|2wTcsgYHi-vPSXAWV7DP?M`;)*Y7l<{Fok|*3~-@vmUw$8WrYqb84|d@ z(q8i!Ruo}A#X{Hx=QVP_9b+rhC5ewV!ydaw{3Pr5_ zvtzEBg|=3$hA^{2zD!T?@Kva09*#f~u2ypRtsrd;RuZX1X7AbL2MxCYsAF_lTFf0l z@eoFcul(7KEIy5dq$gUkDJQ( ziXxT;PYQ!CW5-mydPFl0Xa-LSM8Ew|p=oUB2jWbfd0PhtcF_$zW%R(NHOLK?vo)o1 zZM~EAY+M`7Y3Ld5^{SIKrz&dD_RT;g+J+oxCeNj`B~#s47jVMru^hDYI|jrUd;}lm zc-az3DJ{pi_@!10~s^Ww^%xqPT1|s}2>juf6Xm z!f0+}vc;~BOY7l?0eBxHvDV+T<%T&r9V(}g-8E;BuusEFqy@0>SLLSj%3CLpd`PBl zBlDgUmBmht4RmsOR)BHvafw=kxaWYR%fVL25s1z<{WZ>!W`4yX+%`N?m0HGdr*x&5 zHT+5Eyow6m-~|H!@0cl1savrhHUW8N>ZM`kvPgBZbH@zoF^UNmt2@7Y_v%`peyX3e z{L)I98@b)=^e#=+1lK3af+M=sbz=D0M3YVw^-4kA5}^gL?mDEp;wW#gA1Bc~yEX1- z>m#vUd1G77($=}qXdrD8v+z@Is8m9$B)rH~>0!|}2L2LYAK@0akD=#^ZWD3w>c-ABRi;dHf%tr1r(ot2^S8fg`tS$)#}?1a2J=>sb#Dnm_*OU2Aug#o zC0EOXY`U@Td^I%!6|E3>depYf--wAU@hE0W)P1zG3=3gMFWiri0&Ih85le+-^)Mnr z&&Ku`C(#6G1QWswK4)a-3Eoa4=y4}xRf;K6l%AyEAs2e) zED?w5aH&+gzZ(+wjc~4IRs?!!q{TH68kRt}20HX}vzszj=knq1mF)`D!J^i(>-3xP z7%?D^4Q>zL#X=P2>kvm|LXhT-3r~B<(6d3phB*Qp$Nc``)n)62yjyE>r=QvE#@*mJ z_p5mV5!->H`OT_56cGeke>-yXIP%q2FRTrr#xKX-k4f<~^jQgcd5mhpaYPSyY8j%2 zKW5ly2Z3jZ^#6BXBzcNfRoETGHU`P8RsQC>`;m=b2FS}Yuf3Xy*X6U0bx8%LX zjg=N9c1;dS8;w@1n;S#fKGP`WfQE5^->4znaay!}Z94sca#iM&09kGk(Ao%c5tMWQ zEZkiGk1}b|nTW^ZLhd=G`+!HQUgC}IlMfs>(^IAonVF#-MX15Bh}5p66@0)vv& zL(Q)4F~qQI1#tFMJSaKM+p`=A9A97S>Ab1t^?f`_{EL{)H)>VNZ`ppx3x(O7`t)1~ zY@>CwS!HozYTKQa?EqA%u27fmrotYxZA}(?Z*MbFrUj4~DXx4xOm|IHFf6Y+*u6h> zGG%#fluxB=1HwIf|M^COJr{7aGhu79XmKAprpX$NHKmCZe4Y5R+`}*7ZmwmL6q33M zSyv;sEI8@zIMb=xKRvQ=rEVs(Ps`$17gopBCU1laL{BQ5y#pAB?FPq`wYEsO9<79O zOHbN~dX{D~9U+&mGdhuK3(ziZ7mgEvyRuO^%{xu6*wBzmBG39i;wQw(6|FDF4gs_c zs}Jauz0S|VZ>w0a1E?Kcm57mV*Sku`iw?(q+Cv$|dYj$Z>N|K?UZr}8fRBF)<=4Qz zwz}ipF_hY#O@PB)xVW@mYvH9O*qNF_FbLwuTBXu*cgA{m;XgW)V)=JRt3j2f{rf&n_aosP^;NVkJ+oWBcB*jP0- zWZ6@E>nj;|;9#^VW!(=%18wP=@@d!B%n^M61w^@?gL@en;FKjSVkS_~9yrLrVn`2? z`W`bpD&Zje3Qa|ZLx`XysE+i1g6~&SKPz)&lc3SBlYlTedUtFNvRPcEakrqI)YEp^#E$BD)FuawJ`#th zBt#Skwf-ZjV_$9T7|6n*(2V79Y*%eFP)+utr9mfV3b;=rbrf}5=p0YHQ|vh{YNHbj zQ>Zzoe#riz$kre+sn(#OHc#w@Fj@36O@$n9Oh9~#+y^HuoO|;!RiaCnyUUDehl)O^ zt|~tI#P<6y3e?{BHQZ)ZsAodBKk*u>?*@?}FEbq>Jt$S?-|@8P_Eac?Hz|Nh*@#Bm z$3xl*HfVmdz~g4I&ldNtZzMt=bavdpApB-0vUy4t*R zuz)a?UxjH1cAMX1#=6X7@wcADh!ZXC~nePFG#lVMEGNx6wle zwryb+Xk_+am(-87Nkcb4W5XJIGbyMT=yk=5Hp6jDWU(o;&{37hhEH^V14Zp5>_KvD z{<#6)hU}a#LSq-(7K6uG&tgX~1B(nJ)oJk^#J{Z1KkG>Ka16Kp9{|KD zAgs4#_TF_0Uo#)7%$jtyM2pFSiujZF4NE?`J4N;2HQSz72r2r zz_<;3cpQmY4gZ)rU*|1a{q|9!RjlCYRq(MdO)qGf3~sR#3UMSWxE0hERFpm?xn`NG z)r2CaRs>ls!o${@68+wyrc|mwDj+eG_Dhr#jd(LQ$o_LYf_X1jQeJbQ{gefNwXEdd zj+^XwNlH*jeB|AQdxKr|HD_(}#`-m^g#dmYJrLJ9mw)Hh2_Ogjg~~X#Z?jE*~{c1dWX6t{dbu zW-Y`SEz}8y$@Ps}M%s{PZNCcklZ`oGjGI)CTIT`M$pXObnA}_$))?ocnj#eIbN3o? zwYm=TA&|HWu|9BX8&3S^y^$iE(ew(2(1bK6U4hh#T_$$muFO|l2p|*%b7PxPwiJ}* za}h*cMcXFG4d$11iSl;9gG~~WkPZ0z!9`Ef!|w7iH+){NJGPW3VU&yy1!K2OTq@mVI^{v^fr!Da3LtN-eaDVRoaed3?ttJ2mz z(7YhK?P$mwvw!h-3ghKmKg^f9WnX-Sg?HKa8(e!AN-27jPCR|uN@MU!v$^uR!{RS~ zQD%NYSJ*Nep6P5A-uDpvel7=qhzK`2!df_*{~ss70_gaK3)SZEjj+cI;QW7?xKu~Z z3IG3i1Z&aaJ(5BDV)K;3P9XktzIT>~IU%G!KdLI^&pA4?oy?Gz%hLXjWF!B-MWDn4 zlD>D?IdZ%?+k8hMAoTXW;9owwYn1*U6YCt{3cMX3J9JpLIc_j)R*LBxIs$}fFq#3X zCkz4wsXYQl^3XQRQaU4P*D!qoVu5aQpS9;QpZjrw0sfF%X#PBPZwSa1MrUVE=Q%#T zM_`I*^951A8ip`F1p+n~;+4Un+lgeRV1J9y)fABOvXX{}IebOjK2GS#Iceh7HcGXd z)0#)E;lODVPE}geV6coLh?Z4KlNJInge(u`JG2O*v^ZqTzGtV5rY@G!|JALY;rsO- zJ1txP(oGsiW{{@yv0HEQ=M8`(UMRYk#w!%@A4HpooG~VhGxM>a!(W3PIct-Qe`;@D z{QMhmx&7TPc@MBfH$28);M7Wo7@s7!ISIzW>g+L@?L?f>6FstilBla1IK~DTZ$|$L zRp1&8Lde>i6t#aF&-PNwn&6I^Oh}zYKs~ZHA4_(WvO(HH#J0^CDxQh5?>GzB1X_Bm_qb{O9XgIGP z`D1`0&9zmd7eip1@?a#`w?Y|=kyz-1k^5rcttK$M(k$U5#UkKoGj$evZtS(WbVK6U_LS7SC#SkN%N zTK-GRYbNJBICFFSkcX{05h9yH03E# zey!$K)ALQJ2M)uq?uc|QEo!*hNM5vcHl-$=NrwG);J7mVj@JPg813{l2d-uTDAHj4 zXPLRdIZS+(Tf#ehTEf;rMg;@Sc!O>i8Dv);xI6HEaWJw5fo3b#VhSAPgNSd?u%wd( zY1)b~WH}qFvI#ulxkmkVoG;(1HCxOoR$Mh(%)a$A$^O%~0{Xi~fNw#AF>Ulq|N4Tz zUJaZxhpFuQu{0Jy`=7n1K@C35^Y$b6!9G>VuE=+REbiCUnV4f9s%O^x_Of`IUyv^J zZO~iR_X)d7mv1us5YZ%(>MbkWvuWJt3L>GYL2XlqR z!@RzcqyhDph~wM-2GbhyZiy3-V2s^}U5#g&F7kNkt#>R5lXDhQ$ecO^5^toNr>x}pGTWv?E###(y{MR%bF0*Q{C6mEK3 zrU!FPPdzG6X%R_! zWD$qC5BQG!fXfq%AbhMk1I8F#M9U)mDl}E%ViSC!HyCphJ`sibH=p;qXZ56Ly3J-A!j<_d$>*S+|?HRFAq6cNN79g zYJof7lUeKsbRk9EgIT2}eL14n!>gs3)C}8fGz6V&j2h zoo6tZ>pDEL+&do7B7ljnw*KX#&*>-c`#la>=Q{NiUmjUp6#DpB7ld}2ZhpK>DERpz=)l5I5oAXaVTgz6ARcdP-HV-D&u`v6ASAlymW zAgG`sof4$5^!*9WmP0B9w7S%vn!gyzBZ=Wyd_wOXRrjFJYXY@KSh;j_` zhq$`-o0>XMzgdTQ^rj|_*DQlw3f7{-CPL6ybKICrwYxWPa{5zr z)!(`}F||49A^X#eTmAPmC}??kvM6gIp-Olc6>(go)rwwq1s$q*rLd#4stuC?2B-ru zq?=Xk@T0M_E?PWNsmU+zu5R!MwIa|T3iQ{iT2 zEb?)_V075lnVG+zM`5HL$iq1yzgZC!gL z(j-@3A#2PRy)3ZA)o|v8n%9t*`{^H&-k!RxORZGpFtCeBIRP=zxD*+Kkd=!iC;Ic= zy^d)rFf?2NBPVV3a<)|Eq=#(}p$ba>B7%>mE7xtkTlY zMHfkp`o=UG#$2+B;Ty0x;H4XE1_twHs!&Kx)w*4P{31yP;K#C=m};pLJ-?%3rHb2^ zAfP53G}Pcf`yejcAO=^nJcjhDb4FT4X&Q@ya!7OaxRm_0`nuDj5!#xf?Nkw4?P@pk zWKtEu>qb9BNA(f8<^7w?Y1R$=SXqs9Ix1f2On7KbN(QHm=b&x~iI08E6eHtdO_$24 z5ys_?0pI2Yc*Bd>4!{_O^uh9zTr@5}pNAPD@ue0J5-FUesvI-edN zpH9$H5cbLu^{##PRi|KmD#pw$x67XiAILxDLH=q3o4waUa>3s_X?6oj@DkMz(^KUmwgWu~`uptF6~v${2?Yt5YfmPmIW!9OTxKDAa`t*2?sy|(pC zhjBPs)I>VoTduCy?Cx_Htz-eM%)E~dLXXU0q#oR{a5%9_EA z)Zw7HclVGcy^7X9);s3zV}LX7$HHBDPed*Qfw5AB3>bKK-u(&1Nw#!V2b+mZr+7NQ zu=H|*y!@27NbQJ-ykESjA_2)66?tkcLffD%W`x+ZwI2AYkp}rpcw>MZUYMRW$ckEp57 zYw%@4o=GTPbZE2_U5J3{oSl>m!>q*`+~I9nlFX*CImN`E^STpjPhxlS<-UEYn$xR`j(tYA-Xfl~9zx4a@3>6Ympx zWP`SyI7!4P_16Y8(j~x^xHtB+=d$H6g2#*SYa=0Bo@@e)Zw%n~nw$sgaFv*2@?Q5? z@`Ph&KpK}KR~f|=%0p$=yg^G#0%RMi5Ml-w2xk%s`G00LGyDHtMjz3h z_)R8--1A9y0i~Yu2`UO@HXGy=`f2H3FUerUpTYC~n%iI@shQTvVa!~ltWk?{Z|ajd z)i%Od_H~uKovdacXVB~KfRMlONF|iN#PtQxThV`fm^F3KkzyWY3JQU5*^T+}=Eqo5gxv6Xj1$Z0Ht# zda!rVA;4V=M7$WjZ@2zz9=`&OFgL+zCpa2xfXaV1jcopO87eBAt)$p(7I%I)D_aZ9 z?^g=-1tEwsDB_qX?9ia?o%%s?>olF@=(JOU0;&lYaOE#Z{Z`fjNf1>0z);`WT0**s z>Bi|_`je((3nv^mx%4>e&yBMl`7zYHUrp|C93#adZrHx5HpOQ&Y?v4(e|a>RJQoJf z!#g*+JeS4AAPR(QJOkAvGK#4*luK!Uu#iAcz@53k5}QevcP0Z;@K-WI+k+g`+`_`~ z0Uh`ocb+cC{PggU_dGckewkvuE8@G_?+zP9st3d}ngsm&-ulw_%NkGxA{ zpUA@Wu()TG+b97T{J-(DE&3kPw_~WAt$FezCkE`SXAE)PF1mPhY0{@?Ea48};;@S@ zaz_^4tNknzrt!=<2`shzrRYgp&25%JXHDFX>uP5lMqZEUk9DNp>*h{D(uyA=FtmJl1* z6LVdZ(BP7J#pO~V_eyHwvfh01s-ve~FPoXpH?qDv#L4*ta+`;Zm=?)@(9L}l zl0i?}GyLjcmZA(nE9NQ%4%%=zfMlP}DU*PlzBz$Ah2~-TNCsm+5XPubUl ze|c^o4dmpezzOR>qv#MH_M2MT=@c_Ud8*U37X>i9pB#qu?O09<*zXH^_7 zEfqdta*j11yh8r}F0LLHcjE&6cUacIBv+#3Kx_A8wdLpsr5Bh{M9JS%8)0Y37g z_6=2RCSAgu;VHk)epd>y}`BX`t-|QY8KF+)$8Nv>4xA)&5FV*{KPx zc%a>S7}1U4Hk(K52G?aZpy73RKu-m41_XpTs3i;VPTD0Ph81Biz_7QfmsXH6aN#jB z>~nVeMoGhTuTt{ZXo!k1Mph9LUW-Rt#oQE7MQ5o@$X1j?WN=lrIcRijPt2GoruFjv zXIE3vM0w&|U2;M>nY6aw1Nkw4`ZpOw+wl-GIEZTu++usl3ydlxz{PU|mO);5l9^xI z*Qe=Sy~K^l0nA#MI|?HFWZs`Z+zs0{ZJ6ckQpXD44T8ru=>dC9Si9+YlK#Ec`sKMZ zwarEIMKoHSAlL<5ZKuhqiKgKjNidV7XbBy3mHl7zOLP~lFPmpz&W^M15CN~~XG zauat*1KvzHJ(M>*09DrM^#e`eF?YxIn3CKHR$;Yt!{$){WmFHQ<#OIQEE!&qW@;Ai zEwS?*0mxzbBH4U1n9M7#$sn7_}bVAttl zR+vC3@WWe&#BjkoYy{QFPCHsSp!W*TC>EViLpmx+nyk+b2=YyKW{wud4&jX^?AOoJ zj!>3- zsbyb#`GCje_Y%7|xj}I`m*||s<^i;KvCdzT5s@sK*z}Uw_{LfmCo+I=vEv=fxBkW< zmQlXPWOZN!R1S;XG7>B~_lMi0Ss`MW9N-sDqC~7gdFcn%3 zrj(KeUF{fKsg2Pi!Owj29m@U5Q6R}zvaNLtaUQ@S)(gDe| zUN&R??mZ^anO%O?%I}$1_b)1d-k>dQw`^R_KT~?V!a356uJNKmDdn)G!!NG6P7z-% zEY(Rl{_Zd6AA0M4!#nNMl-=-YA<*As@r9Q2p+JO4h;^1otT+e6{z$-5ufPL{sa1d!1xcC{{gG* zi4MCW`G3i}ZLk+x8xp7siUZ$9IfDJf2gDn}MguZ{;6#D4vH;saa7sYffF|S!Jiwh` zPz~S(C=L<`4^TM-lq`|}45y6%4EOfoe~)n5v7e?{Z$%A-%MZP(mGd}$TR74K6KhB1aji`K-1On^;r5vDMshZnY!-}NpS3gjk^y}E#w7!I>yv}n^~<5EL1aLq(5QeTxssRSfkK?#-?y(<16M|7F2l>p4xuV8KgEXZWOAXhMDoF_2lpN}-yQlK$8Y+Wysqf|FKDg0A^fSRx0& zV^)AkNC)e}IG+=2@n({aRl~;;$spZ~g|;tT6(%c;%SbDfrM;+U3Gv(?M=;hxW_ZG{ zR*&d0RCWSEk_~Z*PzI$|Pgf?jvX~GS35bXfPGje>&TP&>IgQgC7I0m#oy8o(k%Kd? z8`(-NH{h8;$_mAND;Zb2EY$hU-vR@0GIk2%tRzPRnW@~PVYV&`84TS=E+Ea%^=zh% zC-Z7Cu7hyE<)z3C&9Zw~^3g@|xd8n$pL|$U1ks4~J1D)h8SECq_LpU?NX64p3guW& zx_yHdRBOMClYXO7Gd+J8Wxl`_7{iO`p~>ly2A9J0ZHu9uinP>O5K z!YIr5{(WN7`%(NGWwZ=Ed3o!vD6kvi! z{GP1`=16l=p_z-pxrW4R&8HW5xUa&JgAlgEZGs3P{3})6W72JAf7l5U41@L69!W=O zX8rhKCzFO_uqAE5oP<$yWu!e9D2c<|R|BLeq>I|S%SR#G>)3*m@Oc9ij#D@mC;3VI z`d6FbGvG!c4xsmP%PjhV%-|@5-6ZD2E=eYIsD|dvg{2i|G$L}hzZl*Z^Cg}7b~KBr zn%4a}eBEAMMyj+@)`g^$PGhQUT}Y5kM?U9Yi-E;fSgc0;17=Q=fXu$!guHx)s;Omj zLAv9;u3O2|_V)VP5)FVJj+|}EAO{7=4RCMq^S1YM2xY#KQx`2jMyjxzi9vo-R!7$+ zKK$i|?58#fSR~@bUTR^C)GDuuA!D&ggCb7{i)f^EA9CGCtPR|rPa{sNlAhZ-)>+xaX@ zG1{l-2L?vM(E$^(C`zJjH+$)OE|U%-b!L?slWN|qtMyeJwj!z31or2d%`)Q@Ibrsj zqj4pzsq*4A!o#LTwz8%F?Yi81*>jO)5Ss|ol+d6Bpmqj8wS|61tB3U$WPZT?-6waC zM09*pvQRBbI3kxqDOoJ5$7 zkZ%TIL|bnqQPt~=JGaGA+u6zK{^zPmVJO3+4&)*=vGC{Q?p~zP?0XIC;;859=ehh4 z7mDNn5gOgbSUo9J-)G`28t4BOs2exzNTOCG;cceOZAX)?D#OQDJ{vS$77JTX_h196fx`GE>rB*B#d;9_5c92EN!3H%{yOMi9E=&u#scY!v@ z)#E&zLHky{#5lqOV;gnDR?)!{lJhYx%Ek_Se)GbpYJMvF{`5lU z+b0WPm>283OtPi-hB1s3!*AevjIFXvw4NE+%JxdlwwP5diVP&YibR?lt9>woVz6bz zSZs8%38C$7C>4;XMeh*lX1 zx87n$#a>i)AeWR}N1t=lIMiSO$h@jv+W2+CN`nDy^JWH2@Nc5 zs|cRr{U#shoB6BD%w5(7L6IYCl9Ve)vpMfe;O0eo&&w}Fi)<8YDCqa%-d$ab%>4HB zDG-G_2lzTa{4t)vzI%`)?k)vka>8~3xRDCS&Q={Co4R&oF)bV$jd3jl&Yr7?0{?wa z5Y3(vomRcyb$|GC5uDy&9cE8FUFzK6#2U(v$J`*=Cd_C9_3KPZT)8@ zv--_-?{nSCd?J(M9J>twTN>w#Iyt^C$m}}wTC=rdaH@B<`fa7j45N1hyd7Vs>&O3W zSwH!GxiSSZ8K~ketCpW1Lg27WXNl6tU+RUPxC358SCPVu5u_d%dXED^8DJg$P_F!b z3gnrF?i+B^3Z`vu7~su9#3EVHlaT1zBgp^ex_c>Zd(5{&o72Yt{K4Y_T|0A73ha~$ zH`)@8_}06koQ&JXS3f2S{J0bfzp_jt_Q7Y*)MBTuj>AsH0wQUn@Dk(Owl?ih-9j@O^bWUL258cY6;Zcxh*F zxCrC6qqIOvB+)so|_1_PVU8i;5_k1q^NmjqR$gW}m^lKNX+F}+} zq7kC#(49YgoKInz2_5a|X$u*DxCCkJZ(g8ul0@wh3qM8e10(h|=ESb8tK7dfe(UQ` z>KYLAybF2+R3{V8d2Jola&M=2x{^G;ao(?DF&X}QJ9xE6lW9$;j}|}|U>A4$uRC@# z%+=QnWBO+kpfwh?>`*1`S>FIxmdDfa*VCi}Qa z+jkMMU15IQ17x&XD<7NW_3sMZ5LcMP!95D$3(VzKZ`x@2>fvRS?3l@Pl1m%P!}N3n z#?~xu!cEf5?$^iFn9=u}?L&iZY=`ZgCBGi0z(Q-efU#Dc-2vWH;fb9)NX&25t4H}k zPX3fsgxRo2L_SI@qSK5Qo#vEC+wR}-HBujcz$a0GwV{CG{0s7nvBcv;HoC$S^?0zfCY`!k zxOjrBz`#^iWfRf)x6zm-JPfEuB}`4jyBTTT+5AL0Qd6u*Hys#`}XS(NGCpF z#grek-`NI`SGWZ!VeJObw4 z89^}|uNk>pvizGUyTeI_3-?{Y%q2fxE$W8u)l$QqzscwGWaP5%>-tsyOZ(@vKN)r%9_f$sWcd3E{-{O9G_qr1)c{GN?;ra#Sex`@Ok@AAI?oPYdY$27TF zrL-OQPbtj#{V{TFoT(`&Fv@H zhu^CchgCJO?(G5uz~Mmw#zwqZD$+w=$xev*ic=NS7ud9qm)kJ^-CtPtc85dCGe)+> z*miX5sfX@#iFJ&uex^>^d4CdWZoKUMu)oLNs3LMQG)Od^A88eW_Yf4TTJJ*DfGBzm zfaIa@-J#!%=kodXGyUzt#(l6heKT27_^)RE z(%-a$-ECp!-442i=6L6FK~{9*cR(4g4aOLFn-p9zo|4}D`MO(z%t# zxkmi*meqMB4x|LvVYPW3_WAe_{8>qE{O*^>Q@gfJI?z9y`CGuIh#$0?p`*2Mra{vp z-~>O(1oG0qi051e0E<&wH^D0;+RNJRzqo)eZzyJ+BWV-kQ6G|*_}o&L{$dx(It>J=yjd!R3iT2*{VSKtrgxtSlbdbaP)WQWGXhE z?JI;dO8b#ij-b}uFFOln2SS8&0Rq&4LkV7Sa~*(oSe;8erHZ*z8kKsjCW^rm1rE#l z;@|Ad)m<8ZoyTTA*%3h_AGQwh#vprBmVCu32;$i~Ps?q>ethbInM3s}Gmo1R!j+l{ zcya))(arG7GjOV;6>t{tVUP z@!gbZW2G&4n{?$Qq|YbhMfa~Htz#!Yf4>UL*Vf*rN#L2gdUtqRBQ9#LB)2d8{x1IY=Mwaxp<>RBpBi7QY_G`PB<^mh0TN7WX0L-E) zhqdMO6WhWML9MxO*s@29$@D)f(zyV;q#3Y{%^`1hxVW8A2`cj5IB_cceP+bP!F|u+ zCO*Z;_+R>+3`mF0>zP-C$qSL>2umI+3xYnvP>VfCu%Q7Z&8#ogpuL{Ey`GJQn$bHC zMIKACpZ`(rc(xIOV_roh~j}fw2=PS(35`u*&0Ff};t^>HY3IY&?g%G)z2fbXpw-8_V z*ECAo#|E5pk_e!N_9b@?jo$!iZl9OCg82AWB{v5_Gt!Ga2s5&u+$)P77S{$~U0w*OpoTf~(8QYRpE1v2i$4zs@QK~w=-MU%8iQ}gcB zR^K%m;;%l{|LP6JY|frK$BtOd+4|1}$9gLr9Xmj1dvAl0>1?+2I8-!|NRHCzD*kwed_H+xr8&)yu> zWm6~Qh(e|px($FeN)iBPN02=+b5F~jdn*F z(UH9j^L006?jZo)y#LR!B}ZRli0N@86 z!a>H-$~0F`S7D?ZI}X%Jk?8MFya&=+-cm~}5P%j_`4@N4RZe2O@2K+?E=r5Hz9=qdo+)6znH{=D9O}bn1&JyXq za`n@Nc59WIx$ZSw1ZEbSg7w8jMO$tY;mtyUFDPrrEor_!+m$^1F82kxEHYV`35zG# zf~?^fOH8Oe=hBnp`36l^h`L4abBMgC2*Z;S5EzcO6Bz8_@e7xk!BHiGztmF?X@Q2C zBZYf#8H@iYLvl8p2Il$hw|(&tvVR~b70p3?l+q7r2CeUN?8B|13zrjVjy%e{{rrG- z9U&wAKXqnvCsSKkc1~dT1Rf6X4h;_hgaxSbf`A8LV`Jy~zdhy=J-NE=R+ODrE$4Mc z+7x`j;C|t`0)uAi5cZg6NzCW~M-$?DxZTU5uh*}Ll6Xnf2{%X6@*pPidzQy(zdvMZ zh_ZC2A*5ANMX)9G6lpz;igadZwUU{}&MlMX<@7)6e{zr}KVn^~r}<~anNI=9q(m;$ zzZ*w!i*q1!oG$akCrhjGeU2GkeDnoop^nu`ap2D&Yd~K%j5VYS;H>Ax=j3U9F|czyX(jd+4J{A^c`M;@aw4=*u;GsuaN*sC5tNa?V-eR5pt%a{8g{Wk z(SkT2p`oGWF^FPnAc*pv!9)NA7MkcK;lmO1o*;Q7<5Pf$HdW|J?x6)Ug?X(l`!6T}omOK~t=~>>v}ocSui?q0yjW&R~fp%#}fDa(d1^46xl_Zeb=c|KuCH z;SR{pQVO(ESX1|ylh<{JHN#=X|C1g{zpPq<_eGX$wHHMgtI){8R^S1|^@*4ddl6Cv z8jW|LF+L%-^iC9S&`-k`Bc__1Ahd5HD#M15`J|R2I9;TChj#f5M4bYy}q%hH#2fAcAf{5Amv9!SXBfE=BsR5$r@6#8Qb= zq1RJ3X|BVtB3T9Q{V@h$%{u=&U1uHviHaLb`mgz}AQUPicss&ldMI9MP0ptwoLb%e zS~xVkIX2R(;XaySSVUU`&6t~+($n6wtC1SfHzNGk&;xY!mHs`ObL5~1!3BbUN+#bo zD7+ooBB-;Lq_Kt62*kP{njO(Wy0$Dmg(RxjamDaHK|}kndNdzkS}|rM(;Lh9Xq;q* z1QLpRj~)IJ6sq_X1rll>e+)Y~Bj#WK%Rx}A1^6bK&;a-jasu};Pmn(OG0!-D>M_s?XDY{wZ*YEKHnNt-mHbYOSg7fFK_qlL^P=ulm}JNLhP zMp{oHSXzstpAnOenoyZL#fI+S`i}<;J{t(71`bR>_Z~6yxvo#86Y28;m`W#jLGEL= z=XFh_Q2hA@_5=K6F~^XNTi1S2U$R0-9vs%p_+=3sb$lZ#G($SpPdJb#>RO;IRIN$> z)Ftkr#kwqJ&~K%0-QK3x*&CJZUMQa!`bww|I#TMJtuc=RXt8Cr!g|UK-i^Y#p?Ici@H)O_`U8y-92<2x-DPvG!&k8j z9iNddJH(lkD5w0`623_ffnnVlXJY;_@0XB4l~%#rBEuHlrMUubImcVJGWIvCK)2W} z{@$TYM1Oaa{MQ)35$0?W71EpHiWL9Mxz#;hKbQSxJdR|WR7&njTet>4 zB$T~>;*6~J2@~eakWS6L%BZ^)r*Sd2oJC|zB4d!h;X zBtUTWMF+%YV`IJP9#uB6wQIfzu03~Y9XCzAI=kqG{Js8z2Y9|7KjP^>-<)4O>>oe6 zMcgkBLYP`#);qVCRXmP6;$E&VvhpvAO6a1zJ_81d!6TRhbG&Yan4gH|eV<}qId%}& zVEnk%*J&4MZSk!RP|5{M2aq$uOGFa2lJ=tQ1i=D{c+n-}ZBL}cFJ~{Gjh|b1ik=TK zAOOTIsRQ2QSM<`7SRZ{BihOn1;oQ&m-+@R~Yb3*df=GNS)&4COb^+aPLm^koI|@p6 zoPhQ*`LTgM*S*T++cMoT9jy|$b*VYnJ;3nH(LQRazLyQ1*eh))6t}}L%Q5?QRgkrR ztGnzrA#?evXNmv7B&Ae?(=DlV^cTpvB1zqf3H{zVpJzmHI7_q?lKGRd5WTIiynx*L zfNoSSqdRzo-K~+`?UzGpn1d6?4zQgD3zR42S!&@h9>7J0n8=xkyyvm_L?yR%BE`~# zd3$@vTEpISU>`Q>RwRAt9M|0Wyk8phD~S>83bD7xOHnrR6qk0<_M`^yo4?}2FSd^* zR7AuoMXheztykpn^c~_m5wIx)co2{ibIIkg_1F$+H0nNdrvUIB7(zAj_5L570c+dH z%cQ)rR;q1 zj6mARfHjd^aAqvpU{8(N?JI~-w?{U^n1Ir>fxYeQ*N0NyiwcX)vh*q$o6t-T*p6~B zDpyav)xUc?e3LPpS_x@5Vht7;K)z$OdJ0%Im)#-zgL3irvTb*MxsuJ{&El^rTc*~1 z%u-(%M#@W7S1h@`PHHpVu%{}yD(nuXOKYcQsA)`DatJG>Ne`do&mVKTvd4Neb}n~m z>dx1qSO?864{;Xjnd+o&W;9KotOb24BOeW$%owZP^AxnLH(TdU@CQpWfaP7fItP90 zTTWUT6w(FWhn-i~-`Mn23RnaslEbTR+A!H4=&Ge)_yx4l z^q!lJWAFh!L0$g*92oOODBWojai$c#2=0W_ONrV64GT_uzvJD>{fPUF#nLu;I4RNA zWv&k>`YEjC2j%5Oz7;torFcbn>P)SA2O$spQB^kj-%2EBWqu1MBCFDVEmZtZV`|hV zq4=xL?+sd9^}>4TZdKZAE;Dw_Yvs2Wpj(}`RgtD`-Pg&(`}Mr@a4_dWHD&eXRv(Z0 zA`3EH)Jn6r{63RJe>y9&4LIL!ay!i;9?U;bZ7=s0TcZnjF!8&<^)E*h7Q-weyv{dz zX;au%-Y%F?nU*YiDf@L`7gp5TAxLW1Ho7FP2TWu2iG^ctU9@Z==bc7BPTB*&!l}aZ zv-qmaUvsJT#+OQ-YW`2Jmy2A{$7zVFd=ukpZ8k28GnRP|x_(81XQkOA${PG{M~2)2 z7$W3#J!B5lQ5;LuWs#ro%PGQWMd)zF7&w+VnKbTBOmO9=HKr@F69Ncdk5%G#=c|3J z^B1_ni+sH5g%A5!tHL-WG~qw+A?@fPfAb^D^P=hUmz#_U;8&D{K~6dOt+*<&TxS8J zKa8Cwr}Bc&S-P)Ti&6dcF~~Bwr|Sj56qc71B2)!>4+$U#Q2{(`|MLu`JFaUL$czKO z<^_l`@`;bnVW?w%n?s7KU9{w@8%!qD&88$f5PN-=jk+>~3Z~*ICsgQYUV=!YlRs6Y zsx!xk(|-Foo3s7J()>5Fxopr@C;jUV5t~plNit6ry5yaU_w&=euQy-1b1#lu5|w!` z9Z)?u*pRLLDZBmPa`;`i8RYR`24gI-Xq;RQM!189^09rTZ$opBfOu)83D@AaW&cK; zx^F%~WP>n*C8<)3$%_-t;-=OYyN?KiUr~ez$0FRpiCTWtAe7ks8c*IWhvlHNq8B zMO)+vydVDC0gM?8=@>7w4V4-{=eqYHw3~`gPB9UUMK=4~ zVp(88F!M%T8w0-cw&> zB0lkc2^ncJ*qI>VxrI`>$9GYs#vwhNQBHe{Om!j{@8{0qU*afuXb+2$I)tx`aID6J zsmQswi~5;^K6sHy#X;i@F>cv$D$4!35WP-8M;zb2&{W^OEuU0H`+72qaJ_c;c${qf zw-RMwQRQ0v_76nRU%Mtc|LsKiYD>d7^B#0-d%ys;`uMs z@8D#dU?xb=O!5Y|<-nNY{OA77dE~z6YFt=~SG?8Wk~*WdDQ*|X%X^j!nkb?Gp5+;J+h!{ZPB~HWAX1X%F1f7b&Iq$Bwzmaf5HtU zyohPjKWjPY{N(SPTzPtpDxyPtgD^Y#$@kVsdr>ppYu3Yy$gZ_^!Z17w#IYdf|O+a-VbA?0?Z%ZMh$LSkdk3G}8>_y0%GeJu+CPk1L?=aHUzQ zH8Lw#nbcaXkBF@6cf>W+W>Ck{oPEYqCm599y|LSzy}I&{QiuaHKqvaMOXh`90HjE9 z*{CVGM27f?UX~LAG4w*Xh922Jkda~Gm$M;QK>R9CU(V|tGgp&HHdGL0dv4NRME!YMgtF@_YVUjc|vXm&J zDWX`CaBpgkH0hUZk$*o>Tz3@6yqffEH6Mrgr>T6Sp&pn&X{@WMOb3{nvOHhzE5mCG z_QR&4trUb=@rs|X!HU{*MpPdnzJ%Fx(PkmI;a2B2@{KKDoeocL5qM!&k9wcJ9x?g6 ziZILzi3%loG<@_bZcH8V(Tt@#4i6Ax7f8{t?x8~In|a*`Z+{C_d0<>lAZF^lqL$tm zQaOGh&# zlLtH^<9xov>N=4wG{P;5M!MeTK=e`?lU>i}BE6%zViT*ifRzU0Q`XCv z=W!!+(-ts^?Q$Hjy^R|8KojhQ4XrGN(mFv}o_+%;M4k}HP)?O;z}3>-h#bS`8_p4- zhb*VCBl@s-`xeaDBV4a)N(wywzM4%s-F5cQuWXXjb#bsIgb_^h{hOz0PQTpq=k&oM z5dferj?du#;c6t~zqrcA{9npBUM@O-88hVc={xbV^^Y$H1%%y{G3wN3I4y0#WMyZw0`3S}+!SHRXn8?v(l?n2Z9MSICh ze+n*V(sCD@p9icC)L)OPqBkFRU00_Xke<$gs)oePNr(5;N)vD@(W6PCed(p>qh1m& zri_uvqx@u)j{+Ah)e088au`E zVl!!48l8tz8-UHSdZn-tOY<5jft8fO)NN-Qx-Yb#aO;Ch4ihXB18ego_A`EfVT?0C zo=+Od0+(v|!))XWVK5p&jVq1=&W-=4Ri%1pxMUufbG>APXl2Z!?-u?nQ5~*%xaMdb zdgO*Z6%wE~Ad+i%dUu~_+h3(ENw#io7S?<`LaCUV9v)OdrVBTv;tlhFb zL#V0eweopIUE5OGrp_WNS2OFC88i6w z8K?0`S(?5-P8rd^E6T$4&v9H0#@d|pTQQ~{2gZvVt3yI%4H4)pU(*r%XtN~SY8w>{ z!<&4&!4{IPO536p{RJz1PlvPo#_(KhRbBMlGyTj6#?;^CVz+APEy>5etLYsOnG6wd9{}b+~21WJ6kzoU;&xRzFsr@ z`@9D`pv>Xep8oa2v$IZF@1{d~pGh`*3|t|1jFvx+JZ(&m)C95@KoFFi6qKB*#M&h* z1X_~$!gJzZ)0GKD)C|p}tZzhC(E9taklwgK=IUWcz4inCs63r`wRGi>n z@PIEmOg({)S2^MBcr?VsKjhpKil%F1{X%c> zvuq_@7>v!}FK26jq&G%Egg-(z>RGm;2Mh+X7Ap9osUL!b;jJPHt=*W*haw`RBDBU4 z;o8qa`8|s@V};}IlXzp>h2KQJhI7~(&{TGBY6v|8{)OK1ShAq@8@%TiR|yPqPe1v$ zryB9JO9>c>n9%ZA(JFAn(SA$v$fKF%&&I67tMJkmt%kmWQ;_aq)hV0Kymxsv$|Oxr zs(6tO0Qg)JY}(h3WmnF*a}x1&uoglD{tS6q;5_hN&?KOrTlxHL9=nhVo^Y97~g_{w1oCflBR7&S@3NP}y9?>zCgOYuV9L>m{J=}r(5@sGLRK?}BJ~T#zWqr2#S~_myieh4*1jJm z`)c>-{l$|@)7;zWngZOu{%8w`*~I3P;Dc&7y+c@eRd(d7)HnKZDBf@l<@* zQ=Qs7V9OJ)a~yHL^CW4uRYgH-)!~Z;8M)?8uh^lhtOFs3iFv_MZ0@=;e(tt1zEJ;b zOK)-U@f;I}{4+Mg0rQXeA*J;4t92SAby|L+RWL+TiSxt@_rD{Kh~dw>Or$UCR1AJo7l*Y6H*lNYr?+hTvkk zzEk5{}BQBJu+A6?EMK3)e?-kH=KAPC1S+0t}p)k)OLBKr-2B}wW{ z3GvEoD7Rz%^>b+3ovWfnl}6Vw>rqkJ&1`FlH}zt*!p{DkX2HGf6Fv6ojDDu}aMfnv zgL;UCXB|O)zC|pe~(By)koAaY$#F6RW5(HIx` z#*i1sA=KyXE8DZ7{)IJ*yEYAQ24-dmF@2`I-}njqdPIF9-GCAjRAuE=Zdg z2n9mN3S$04!~^<;3Lz8+p~Qkf5X>JSEXa-6n;a))1%dx)h=U$rA%!yk>Lh@;$$(fO zhsGe(e@1S}fDrK^(k5?zLg7FsguFKaalIjVL&p0j*aYP89*Q%*9gz}3D~TC6i8#K;zGz>`$Us2A=u+*yc?*iW2!Q9E(R!vX=(B^#JT9q47h1`!Fd$h+~M4?&^x4k z=15!;SnEgxGhdXOJC^(c17%0UNa4-7x262X2Rd2Yr2#|`mWuLtDv0U4?N$U{& zx)6)&7PP!XX2=Dbq>jjnwfLoS< zm4kF70f(LT=gT^RD0n7HL1cfw_pk6&IXSC_ma-(W#qHj#KE8SxSysm*H8*{zM`xzZ zLf@=$iNLKY{7G#t%Qv{hvB713yq*l9DI~)wTA=ZWsCsO~Tw%^llN!BwIL(h=zt-gNxiPvM-LrImc@BMe#IGZ?kU2li z$l$#hH}>XERv$$NdSfPoN=vq1%Ts;FA0Qb7d7H(S%>ZSGSj!cY#3d_J|6+f|0g$QM zJ9{}e{*mrY?hxfVwd!q)aq(U#PY>1uJQ5<$y=zB)s=1n|y zR4|J4>Bm+{UId${=Y^@$N;$odSBV)i4laD1`0Wy`Q0H7{pCp3-8ZmjiGh~$QuqKlk zutt{%IQQr=kk0zPR)|Uoz^QlPRDqbuY)Q|*8#=ov3>k(;ydzkUoNw4$Pp5+h;vmkk zBk^Rxn_&A5dt$nNW3TyhKM(sLSVjiC%s}pFG%~WLkKIL=WT8h-!k^dDp$dN2ip4x( zWNz-!WY9pPOHhep(x+p=8k0gLk;7<4`eV~;@C2t(9eDPoE!3lK64p5;cSIS$z#Pf; zAn^aC`c~G*O+)}Uj-ZGV&zj>5@bP%nj)Vy*VFt!c=HZ*bLTWAd$lsaMm$3Ih5lv@) zBQ!8jyA#GiIS)rosz)koPuQl%5Jo%_C2XeO6XmI0M;@y*h9km%C#V76j2op<5#aNT z#BMmW@C7;;3Ojla4%)ZXwh?;Q<_p~WV7gB<-=RfpMBvhwSW!Cgf{l^u0CH+k9I(cO z^)eDqjUM&1(HwK+xX>R~T= zbj+U_T|>~Uvsr~Pc)|+Mgy}T}1i5;Z366Wzp^hrT5}<2Q^yRz~5*MskbOI;ZY{wX~ z&Q`?Mw{RgQM1)4yPjYjbV8WX1~l=pDc({EJrg`Xbi*H7WB+s@PU8Pu?U(T3 zI$F$!YNJCB3uB@OJ<&xRSm9B|5pw=XsphAhWc_3CY2Hxw9?M}|9*F#i+DQ4@Hz65L zJ5dN#S@|i14T4#qq1m`1OMki)!ZUG479b}v%;1ooq?rAyc0(GT#|yoNn&P~W{T<$7 zE<0j3!VzmfL64tRoU+kQZmu2uk9ZvvYHzG|=%2EP*WcsqK17+&`S&w7nj3bf=4rW_ zw5N_7e$KvLFdGQSWNl$z8nUM;00N67@~vuo&zt)dsZl+6qd-&$^_BQ#7GLuI!9mpn zqf6Gx;$St2T6OjQ9Y`$?DHIs{*`KF#a{}5AOd6OI>FZZ zl7y4CW#3B_!uhWg5v8eyrU ztE39Zp!4YUyzbxD$D-HXJ8RZ1;iAk}6Wy072l zvXP5)gaxNcR^@Rw(JF1XWtsz-w6S!yzw7TxAN@_VscX6*U)~6xUiP@iijVF^V6p>y zbmYcy762Vrm__8vsb8D5vtZA&CUA)gsyCL~}K~JV8ha_tAb*3Nm=+x5_ zy%dE_4ynPOCX3%!k=36(O%9vB*1ZvNqI+-A*z; z0Hb6gRt+XfRee?d3@0q}6Y#6Fnlm!mtG{b(SXOyzr+`LnDwNlV2iMoTO%g{sFFt&Q zOwL;CnLq2k*EWdfA@n`THicrwYQEjS)cXTiJ!j+8+Xq&&3b#MuoUBP(GTCX5X|GFb zFxiRZU${2ikLXBgA1sQki~h|u`*qB6&ymTp#P+4ctmPz@llNyg|M&hY`kuHb^ZF?n zq25fiN(ou4Uuw5MIL0=|axm$0T~1%i>c4LN+lJNQVtdQ>{#S4u7|it5!`_5RL)pZX zNlH{3Y{<#NYRK`;l%0*u^qVQO5eqv9GmFVLc2;f^RzUy&PNk8a$ z)mL}qhZ|00En};h-=_;yvQZj>DSrmi%n^ARV#xOD)tPi_B$2=18EP8;JPmBIu)g|+ z81jpxlbP^y1&p{M4m@+%_#Bo|#rqyZLf0O~IowSasQ2UTw#h-uEchy2RlkOr4%&(M z>cil}Ds(j>CrXcGsLH$)Iws_W1K<*Gk367L?&Ek#o6~U7PWUPLB&y*mA`%`!=_R z_n*Z!kKntLnk*Y2`R;_+X>_gWHVt1eh)oA)RnWs!meW*vuM?Whl-j736r&UQe9>q4 zj%*`($>Kus9ARMT@-hD9Ojf}GEne9vb3J`GF6jP`yH7eF3pqF^-fZ7>HcXeobPG{j zFDa}iO%JG@;COR-noTmWnUWioNl)z~m%q}i-Di&z5_JRPR@i3^>X0wxw4))YPFE~Z zdQ{Qv66 z?49fSVJHCZJf9GSZkjuC`S`T~zMVbio<;1EVTU%Up?*+VrPSc?I6mREl=X#H`RGli zwYN+X4{v4^udXdUD?P)iSH1AExM< zy9cPL4elZ0x1Anan5bgQxVxLssfbg$4rDyoE_Q&9D0=ouOvE|89O?mj11w~s>(@z= zLM&g-Ns7WI4>)@83|dcAS95f&+8tl}jAx|ogUcW9%#z2%ldnuM>fhMQ@&PQ!CbFlh z+X$r3^N-o&*Z5Aw+x5gP9G%GOJ@ucQ92!E^A?bk)><_~(TyJF!Bu09n>2u55ui3>k zWK{qeMxkXuj}oJ2ogLKIXty`Q{Jj-j|L3@>VCs(Q#Ye&j{ynZZ8y%5qB*FY~J`W_W z%@5v@IotIyJ1&kSQ$QJ4pJsj7j@*TzPJqn*p#xpy2z7?oV&9;m*`TW<=Rvh^gibh8 z!D}?1J=HLG`j<;i4_f(r3sNRh{dPBV&!51HgnqYfJ*fQWNr9K*Z3}0!zt_3UNDiG3 zNdsL^POB38hOakdMaZYuJvu$;A@5v(2fugH`%7k6BSbz=&=0{PFZ(2jB+jb;!S@0y zvP?iXF|@C7hVti0OX#^#ss(ra4r0S+wMjyX!_*14G=;uKY!}@_uW^>A1aZYxOab8Y zp6j>nbURs(nF4mS_sZceL8#@~2%7JUEmLfrW)Mdxor|JMeqUy4uS{P2-!w%lDp4nXQo9p|KzB<>C(;6(+Jxm-Do;RX2b9fs%}@mmw{sfx0os=RsDTH zKa_*`31>rE+Gz?Qj+stgf4^-R8;@4HSSe-x_iFCxt*DKX1`EejZYw9*C@k&#m(+gz z4Qm@9@PJ%?GK1$RsIK*)lAHAOCMst?#1e zPHqj`Y)x2oF-9%LXQohg@%;&<{+%GB>P$N@QJ%5ps(G7QpAyE z^8g>Ohs1#P%1%gW)aW(p7n;qiCqmZfjXR30A*W1yrc}lE!3Igl28yn=p!n*F{^7XA z98YA_K6V4qWJ?wwqwByWvO~QbiC(o0Lh`MTo(tB??70aH;wH>08O~V;?1bv_z7zG5 zhDyg_r4e`OR#7w3J@dEcVMJXOLslWM`lBF;KiMnP1 z(Bb+07e0aocOeT0jJ$cgKi;dKZ)XGl%@N1Jsb7Dja|tqV=77mF0KNGKjyB4Uz);M& zJhOpS)a9)KiAAB{bC;{wH83>~y)s94av2qitPIEqGCl&P2UU26zFruJG2n z@r*ZawW#q|Q^m0O4sGQ5yCK_hKRRuUbSwsy^sk_N|D%IO5bBVext|h>@RT{tE=w1_ zt*L1$9RAnqS<9` z1@|>yd8=kV>rdmzp+%7)1RS;k!#2RcHNu$w&iy;R-7a-X5UN?SDS9HcUw!aAG|)n` zWw^MxuyJ0|H4&Gf^Ps_#Q*b?t^Ih zhzXz=(PnaoXt3|lEMFUj5wU#(8~#`>TMr505cGay8#L$i38^pm23(*>@a=+5E!cEteN03y@(tm$)w^OeMk12FYxYmI4P?M_{-UqHdiTh1DxpCAMda4QS)& zkBEhI!R#o+4GUSUkp^AH1|G=3o=W=T(yu!p0z2r)-ON=94r{$pedPGib(CS0+a-GQ zvl&&JZFa*2$_`o|L=bV8TNc2*)1t?6{ESb~3MOUxsaM3P0nl`3UwuVSliA0j6A5qA zRbwA%CKFBu@yIY#ETU3Nr?wxFXI>8YGq2?KRoJB)l&U>RF8<2=N0OxieWy$Vv(kuu zEs9PlPr=Esbpk~LGW7LAl~5x@|2TYWIJI{Eg{Bn!w+PmI$t$5nWdoOp!-GWeOO}Ej3X4hbsliV)zE#|H z|7F!_0b+$xj0jU&{Lbcyg2Kd4D|L^gak(B{-Ao3guCjA&%fdC@$3~A56DqKtPonqr_GVUm^^Pn*kwO_F2<0SZQT%tvA2u(D0Sz zja>Q`CCtKgznpJYb{_xj%#Lt-TvjD22YKm9GA>e~d(JXZuomZRrK=ZJ?w&E?$+T)8 za2T2pB_I~QL=rjNh$>usS}oVbVrl4U=dqILKsp)x&uY>Nh*LF=9Ne5H(MKk@afTMr zzeu=c-SpwbePtq75z^hmJs|#9C%%P*-^O@ zG*h$;Q&anJOG^px`%^%SB=8~fw8S`+dCbJn3Rlg6s-DaG4^^y2oKW77{Ycw38RIw* z5P(%SX~u3*f4~#nz;nA4?kvUkxV?o0h`CTXL-uc`_T1-a6OYpPbtBVan->e0QjV&2 zbz8v=&s&Q|cvVwpT+hNA>oU^~DI`Zla+ z(KY!cusAy_QDt8|f(dRv-t%M{z%zB03Y?eJ`_oGcoG(pX-_~XF8-H*5aWoBp4#p~f z?szA6QlN0s7=80(q=dymRUZ%pDJSszqgK9D_nX6?-q-YIpg-B&THbwRICy^iUDBgt zdnXpM5*=@L^>SKz1}9cbeQTrSOC0q9KYni$Qu;Pa@>>) zE)g4~hituDC8#1Uf_;DE%~5f|@iur~iHNByR~>JjQ-d*Zsh+;-)Ce&1Sb8scPU_)Y zX>EFmR%=+t`1+@2-x^9XTK>?hKgWH_XH(p_tiTl|PrawXRu$(3Uq;YbT8Ti6wlcw> z<)y5*y!m=^sQOyHr%2yTiDtXTbD1?n#s7sivl%fO$lOgKgYQO`W#z+FS-T4hyH2s* zoT%-cV`v(eyyiA~bpiM>1o*X}B82bYdYb^+1Gy+KHyi)6(y(F@8LY2P7 z8<{0=MEgYoqxu|bOG6uu5_&zEn!*y48L&3N+Vv!Zo^W+1M*Zj1LsGIpPDjKifk7nn z;8@W$446HTz9DP{|8!r%>NcOk>iPzcXi|hBWk^?H$ahEdZ_2#~rNF!PpMj2Z33qB* zRP0dM11q9gK>%JH%17P<=urgT+s`iKOkA<+Rnk@c7YYk{RFDn(+$O$6(_LF5nMx0F zeihT<%-Bvo^^`4ohBy5w2kLa)j|8aNo&gc#J*^$rdKFI$n66IYm|CzED1)||`|?aA zCK6d{B{hl3GAxc2R$Ka+2e||^}wW$myn(gbz0fdFJJdLL#IvKb)ig;oEs|nm#K@vX*!efe3^N-b_jWgDEsh%kuUP=HJ!iG76%|_ACg$-Y2pJ74V8_@S4~q7ie!imS)gsGF!4;v1g-2C4lKu`%P~i*~?}_6hS_4A2eFUyf}hn zr7KDYePju15T9ZqoRvvuQ!CGya#f+aM8CU8gH@EwbB>Gqm`e?MU4)hLD3%V$cp?13 zCh#jViNmyh$KI>5Jq`D`xf$2LU81#EUt>^yCZ3|B;sCs7 z4FIewuP@M8YRX$mx*-a+6-oWyLxyf1y)PWvoigOJ+?l%d)uEe7=f4B<*SN9aZ3vv< z<=`1TkTK_j%<{d?rDm0zKElT~q zaZ657qfcQYsJ^*p3Nr%xazPE@{=D9a%({^qFZ9HvIIL|&3gI(QRyIW@rECw6Y}ZZ_ zHD{C34PKCPQ}FLiMxD0SEZY{Md<5hIKUY?6ZjNAoELHpL%Us^UAe+G5GrLqnUY15L zg)_)^nO+MaZP4FVbU9&6=HN2QfbMxNvO8U&eHIAP*oKZ7zWGHJp+dU732u3-w6y=JTWjpHHssZ9TpgdmxRGsu>f$G!7eg$y+;JP3 z{=}!8`I3*nK21+@SfF=@ywIQvjFIcm`WGgjnH`2PkCv|s#z0y|I?s>rS)J}VND6-U zEUYfZ?gUVMVUe3$9TSq@xdZw}57J0c4$jN9+3QTTP~<EaQTF$j-b}qH7&$ObNWw?&=Lqva-?+5$f+3-o~?a18VFI}0P zQQeW)4(~~0jR5`jm<#MR3n%*<9B;tyKo05ef@t`fJ$JU3LN%V@x`Ta4thhMsv zSD$JGlJaK-QA>K4&qN-j)%-T}F;qRFMY%Kp@5s<4X6Tig;*Lz!cM_5m*#0ZOZq;C`S+^! zp1!kt(aO7dw(BWLg&wG`3D|apM2ndsd^en=kZj$Q?nyqr~lo(a<8vLdWd} z{8}CaX8|lc(8J)(e>Tr`<}#mIY|z;eVW`?}Ln;5g-ag+ZP&B1Pb5f9txF-f#3YB8= z6y0l(Ef5~i_X_!?Ts$j%(9tCJMhqKFqDQaPQGC=ha!drz13Sx@;?zR9^g_^*%iSmW~;$% zwx8Mrg{~n}h{uy)DM3ERR7{WPSu_0|H=WfIGu;X2es60c$V}LW(hy=lZ9+^gia@6$ z83TZM#@E6`?ui5Tj9E%_|JrOa>3X^pB|bE$a+VzyfipCEG%it4HPVbSk<;qr(~>m<+70dey=ed5f(+F-yiOOgU_r6-cE z5S`+u$ZY7bQI@at!I;?-?><2tU&^l^eE}kM;IE3fdEpOpWvE47p@J!;avOA?sw(9h zKz;o>>*EVP4;IL@J$2X7J!uYk@0x9b+8}NSfkldrzM>Y&Qx_$h$f>DKt}E?l_vMyt zoA`8-7j$~bS~uhL>iA!jIUE7>Gb(l531yPhe`YUJz%(2S3kAa(HdX+7kES>fn*gx_ z6t>l}TNlqt>aXY}J8bXLm1yY4i|Q6lvg)^&sWtfdoJGCKDb(8GAp0#CM7o^bZG_sB}Ti$wp`T{?b+XZ7MeCyuV^ z-Or2_%zRYF6{F$11_Z{Y>3JVp9)NT!M}~cgehRDJv#3DOkLt4st6g9%j?jghl^YgZ zbia6LxD)8|Mn6m^e+XM6kDUVda{HCFE<{TeA7W>kkicc&F@)L!$NZPpY5YxXVOg+3 zh2NUn$A(HpVdiM+ka?votIbwt=3*UisV$^XOx$(vSQn&6EZp|{kxI*dTuMskaQl=e zujkUe%sOs+q^pN341YS_cqHTO8lE&U5M1F42VfAtn%o|1?E!Ai4KW0uG~TLR?_M|^lx$(QL7XY+wKaux z88_O{*2I}PKyz@}(Dm-lgzV2~R znvoULN!Sto0CS}qup{t;937_Tvm_dN#p5d(A)1G^B z+6Ol;e|x`uK2AA>OMoh^V8x zzYSWXTROPH`)`2%1$hkM(($h#$p~3-olWPQ?Z@Xp(ib%E!hTWPp7aNWle`yWy+Iu= zCcAwSImbD116|}B0H+EDpB<+;6ZSw3pso|*HotUH0$Em62LS_$GEd}3(hj5CT8_(S zlj~OgX=Bk4L>Ix(Psjo5n3S;qa9T?^M(OsPeiH>d+Ej{ovP(LbN$R-{!agGH4aYQ- z00N!FVtrRWR->irQ90Nw+c~Y$r*TqB-rbR<&GGxM5m##tDYVmuQl$ zs&=^1n1lAJe&o^;m)>nWk*&3Q_sJ@COtnI)FVX7F(VZ52lwT?;9;GxY|B1>ok+8(^ z=>w`>y(}Sdrx>ZCIVL(lTE>zDDO7Yiina^Jj!QrvqoPPLS}bk7XaAx=k6>l9pM5LQw{2J2HbO z_8H4$1GBb-KI5TQHGrv#JHO&wpf)N`MQFI0S$qZ}V?m1v){lexiLWZfa^|OF(|8V` znW(50Kkg4x6P#tGI&h9Bs=-YE4T?zW#@N@VTq(WcT0<|N1sS4N1Bs7GMbDh%TX6Dd zt`qSLhguGxpd-%RC|0TKwR<(BEkGf%SN(%!GQ{z-#WsdlzPHdU*ErH#oQa89Za|4S zc;#m;^PB&}`t7?Op*1yXdRo6sq8sC$vk43V)c$vw!t5^b9PiJ;ref*h`b4L(a9LlCFZ@#J=|U_VXg0SE$soNN2mtt z+vFTU68LK@3nk*MSGdNB?^})zge%#PX#*q1-Ea*NTF;4d&><qxH zzf_DGCi0}{?H?qZub>*=)#{bhyu%G6wjwHnxR^~?mlbfs6?&(8`TSSf^h|=DM`4XW z7dBX6&V}g10W$Bfj^H1ECf3g#(^zposM^Zoo_oC4xsM>ElTeh8TGsKxvOO!kjSIE; zmyy|taYb#;0(vyvc@*A=g3;_kS*?+ZDeusqxWje|55@FEx(j%^+aCl)kn`&F zu|Ej-fabox7)Xx({e&sEqD{|DE`^7fjJc0ff$nW*0{?=(vEqewXgK!o0|+HZSJc%< z+K3Hi5gUORTDgF4U-IllSNZwxuI}X#e#w|s_{yyTo#57Ef0$HtFS$wr^zs>T$8vap z``D*&2JKfU`SwXIVDgpYDJhOYIn?~K?biS50oIYvKY;-|{4Z?G(+nlE&YtH^!Hlx$ z^=L#^Po-*c<@un;Pe-Bw?iccmfn)Rkj{P1@8%bOkrReI3&fo=7fm*M#Kf*jd9eSj z5OYd7?wU-Pa_;m_;+EqsB^^U~sm+|#0yZ~?Uft}KD=La<=?jA$9%;xsWG+7#JNeHr zzM0MQ8~74--XT4C(0!PS;df^`;#gZnw4vzON}gq+RX&C2$=IsI+3X;jJ_jB>;4MTV zO7i!AqG%iMr_rR=q%gCFbGcaE99k?PwC3s?Q1Q(X%j>ZaUtwSH_RcKD@D3Y?o`MM8e+6H#5C zF!pu61PI1iV&ORPrr+weRr4;WXZL9(aRh+7&J>VCT<764nLn#ZNGfkmS1jB9Y%x_7H7Iqp$Kt1euV^#1dP2Y51Mr zd)v*b0QOS#C7P?cX{Qcu`zn6DlaCYKkH5E5S<>1+dO1@z@?K6>as!Ne7`H~x&&hCK zJzu@P0DXUdZGK-@e`=dZr1Wwf9ZZe%*W>e#F|Vy{r$E);q1gO(yX^3f{Jg1&4&}SY zbbdHU1=#0Tf{R;{KD}>1&)56Y*1t+2ZejN9mXPWE?*WyA_MFOvXBiqbiNJ?{C5nAl zg318DL9CFZ0WhOj0$HfD=Nh1#?bfoC;dW~ffHa~LypAn}&;2@IQ~1$$7{)tmd{K`j z?Pm3TK_+`l;pWXnmnetinIpERRuseTCYvw(TDVH*t;vrO^^qPc=7LoBr8rjN;s*k3tuuZw?(}0OP-Z%^y9gMC~nCN>f*{wqW_YY13ri0XuHb8oaVj;hi0j(HNXROh&O)}dUrcJ(m>h7;AncBz|tT&aI5=P`JP zO=QiZ;=Ea8hK-SI;QkJGVG5d=4xX{TAE+6`2bFwC!>0>gJA9xg&t6~i`(Nn%1Ee{y z)cQ>6DA{v6gJKJr1+{$YD)Zea9Yxk>#dw15{@F99QLz zcG?-}Rci)9*+9SD4~;qOry2ZIupK?(C;RnJ(*#D2V-tn5-)dz_T@e?dNfD;b6MpqS zPMHpywGCpJ4`?c&mhYpvF#Y2@{#N+5Qj^G*SbHll_6Wy||Vn?uue& zpfu>vr@2T-BeY_?BX|*s1sorLySubejp&TyQojdq3u>Vo@K?3I&WG9S*uXx$Z1OKi z8r`R%E%FTVelMnB9!oC1X>H+fR!F#qwhmzYHJzMhSA%p@%v`F{C723;nLcOq7FUES zna}Y9tjv8@vQ$8|raG}Mmr0_S5)S(#qEN?inhFquMiZHSISVK}1HdM7v0KDxNtf-g z2xD4ka1|t4UmxJ6A<}}y6|I1?O`|R8h6a|4TCM;2&>J~zUE~ob3=*Y2flBJ29I^YWt z8i>+l<;Pe&?GeZOfRp1$_YR-m3I-|ArEQAq3>Gi;jS%ydTuuRHBYGgd4NZ8Izkv$; z2zxIAA#<*qLUlYyw_ZP_OzX0c<)xeLS8@}NuKFs{mY$T4>xPJ0Phpb7aK?E^kI;K2 zOX{+#Mt_Pd^R(nYjcdie7FcOFQ`qe=m!=@?W`ZS3BwTxf0etR}U6*-nnt=ls!JF{< zpE(Z(}lFH9TuqYsFIqiI_Pvb zg9wro$Aks4 zvY+@b!-0#Y)7_Nr0l8?Ou43embgeMGU>A_qa_77cX~QeN`UPF4wTz5E-B9+^&2fGQ zq+A4lw+YO-WGTPj#9-IA4NPk`2w*mqZsU9qNnp1A`w;j;E@>m}J=)(&`0Dk3n*Re@ zQ!N^oZuEtN3e1#_#09Jz9_)|spAi2OQd_V;vM4JE6IXg-3W#zzZXUM1_a#JyO}Ak{z-?3M!_t6AuK>nIYwI1sy5a@qOs@jQ&H`cPPL}|| zE=jK%!TQgV44yH4HxNWE-5V4e@jsJ*5qPrjT2Sn^T2P#uhyP8?ZG$g3P2j+siO6Ja zSzkD{zyJSkRP5g(rm16{*xLPZ#K99Ya|{ zlZzBv@3b)|(Fcq&7>)boW>L!&0SyT-hwOq@q_Fg`Ryp*|G$rs2{i5gO{Wt}SwezhB z3(y7BDNtqe{bAxlM>xrBtH#yzaQ7hb#Nto5;3+`n^$C_{Moem+F`zWqCPqNoChw!5 z=>Av%%><7PV3=}7fh+-im3J}?lh!m97h~yu=qd}s{ZaXVs7Zs;eZvXdeVRDiRmN-Y>Q6xG(3~| z^o)OjgQ^m3OOK(Rf`q9jXrN!D&;LphJ6bL0Ml?v5VXT$F>FAaXSfd$L8vYe&uLEb# z5Vf3DN$UIyP>z0OBcd8{Qdb;d*5Dn(@R8~!ad1sp_MO0Juld^`4t7y0AtQwY)}j;m zYQ-n+g11Uq=yU~tgsx$hj84_MehIEq07?^rJx|?Sz&432-E3==gWe2d355mUOY1z7 z#2|*C1HMbGaAOmV?inZJ3F=c*s)REMQLIMv$6*5o&@3vaGE!+fOd}N-@?j(nhel!* zjYes;a#XRzrv9*uO%;TJXEC597wd@OT}iEQ`sY^ZhQQTwatZt{c{D=ZG`eS@;kW{} zS?B{+fqnU?sr-oj{R;glC{EOS#_6buvqJ2;;Yl&9^EgQ*(l!vsj(gTeo6iSSFNVAu zN@g_<5Epk+R*@SB0gP@4t6em4T3}d_g@e0~IbYOQgt|I9L?#9aRJ$L8PiOfbmU46tbIadP z5Ij~U8}gD8la%J5WtL{R84MqIzclHzg99uhfQ&Sk|i9TIcYr%REg)qU> z?=q;i>7vgYO7s2!dP{Zzth7X_U}4hnA_}`nh;m*lk=0r=i^4dQ*EoG+C;@)NkYE)% zAUKOS`j>s6?ri}1d=fh<3LLS+PStgZT`ZjJ_3`XMeuj;hr|2xxD|&lbLOOK zA-fBa_Q#t&^V{ahwYR+z0~3T;y_?XF*PGkho%k`HGULVk>Ggf<{p@|Cu~S#>q)8c} z_ubqzju3M-m4T&lm}P_CAGLU;Q#8aI@H@i^;3m;t5r-8|iJHFeZ6?CV``f&T2YbB( z`J+e5C>DHUDLvIsU|VsZw~s6h3(w4)_U2*Q=@xDe`67*zK+Ts*_{2*ZFZqh&5^TyS z16dCFs;({Mfsk~LkVB9BM?O%;&G8bdm9-1j3`#eeAy*)>J+Mb&8^#+$B?3eru$~6? zd7W5l$FqpB&%_0vuFi5Ggrf{`89(Q=l**wio%z5sLB3XXd_aiJ4I8+3NCx|s%a$;U$aK)ztJHhf_-o!QK()|4O|uTXT-A7&fBX%S}I zEbL_eAJQjMl{B(~aNEs(+CH;00Qjh%Tm>6l+6zYE1joHaoIWC{C79mNln1IKBssxu zt6dGODw9SlFamrlj8fx+%(V-_9+6;6wLc|`T0@mw`B`QE1%DgiV=QP~a3}Fk6;XXy z@;p9I`+efhI>8vPS5>|rZOT49pYj%DHUhY+0=S0Zlf1pN--|AS~6uy zA3vnaF(~1>D-leMI>Vkb5sU$TB8mt6MxM+FticIaN)et^ga>*jSCRzY)0QJqlt-=T zh9CSwo-7fE4q;1DxQ-wM!23Vui7<4lTaqN~&L%!6oxF));Ew0t97&RYeIh6eyHKS{ zfZ{W`mJ`7inqyALTs=sj$Kma9CCN}CJ(q`#Abr;Iy*<$@I)=jOxG|7BI%*sGGUn8~ z3p9bR9v5Ks+PCY)#{Xj|ZBz~0MgNvj+m$djz!uk{-;cAc-IxL1-(MqVcF&*IPY>o_ z72au#3XjLf6HprXgFW;enP9xIjwk%0qG|wB3xdtr?c!VgVMb?VrXTtbVX^naDTKx)h}#2QdHz^vvu$!IsjCMO%EV>2SvR zx+gYvN1d^JFt4#pEm(;19Z!|P3N(z3j+93Hnl)w*N|d^x$6}ECk+b6_3x%<%3mD+w zroCIC<$#~5c)}k{o6&%DPLKn7cu%h(&(CmFU}Il>dPdCTtrg!y{~xB_3h_Dvzt`_J zg&%MJUnYRTO!(!nLSUQA%B`*u1Yv2kB+fwqcUPLJ|gFu_+n?F>HfNHbLL z&9($wwhTR=+ak+@YU6BlYeX;gCTXO?0#PV=#2N5><=ssLUN`EdL$hHFmtUB?^~>6o zV<2aqFMdnWMA>v)a{p=V*3-Q|8oK@{K_1C>g~%tr_r3oNN~}4Q=o{tm&L4;o%AuP4 zB)eux)%}pkoZoXl0>PgDbsbqh3Qa}TEJw)vL@%*7wKRzQUpY(yc&@jW^ti-$4sABoWf?DBm69mqF zd{=xGimGc9AH>93{U!WBb%(R5>GbUwWkcr(Bj9+Yp6=49%i{;U8iq3e+WRH`E4cM} zdEf>#iP)u<IW$eq(aI=;c0(^7f_#dldej_y0y-8GoiZ5=}p$ve!ixL`2y3a=yH? z_oEeUsw{u@e%xX-cUq%NA#uA5F94azQ?{6Cb!vQ6@3te3y*(Qyl#KRojinW^B&!KG zZ}vS_kiLnt<8HvC)f)L&#CsRj9$^kpTf>K>f38qhJN#&472?O%kW=G^vPci@Nsp4V z;c5Tu3Gj7F@Bm(?nr;CD zl?i7`6W95cPXsO6Rm1)x(vy$jYE#)iP~-6|y1HE>Pbi;#9nJ5jmwo@aYwH(C40-dmYdIKS8PYchVhtD6y%vJ zyi5ds4MLd(=lu`;@YD0~S_y9KS6M^H93qA2YobpR4Nu-ix8LKxXMvx4i(3C8Ku*t9 z;n~1T5~pZ<=fZ9wrD(^`xcI z()_Vz%?x>RfA;l!)TZ(Hc<(TEDaGDHQ>VeXbi;d4$o6$2wZ-zFcJNmkckokS&A0{5 zjOqL{XOSu*DL`*a>Ef-6e>J0A@SiQZ5gQameD#(#ntVu=04FDLGgim~j~x*fsICsa}6 z@O33ez%lk)3&Tlc(+zMX@t^$>J?L#qM z^{cd_dfc1^viN;jj~7QCbWNZem&t1<^NY=DGP)mtPwyV<;!)AQ45{EcO1t+9A*iz#QcG^$%*Sg@ zWP> zgU-4Z7*X4Y1MEWl18m$utEyOaN8=_1!?zKR6^Stkh9&zFC3iJt^OsL;=nHktUqLr3 zjWtjUBfNA>ctwx>QZeYrMm6%s9HkC7R_?6*y~f6BsNdjcYj5o-G<;FI0{sn}C%eG6 zq$XdjmO6169Jkcr;kJHspK>|F?~wu-rYBsZh?~4u0LdHIJ218Gy^{_`c1E``D#TS9 zj}(a~FrBbs;BJa&e3ng?OFnF;ZkdjG^8Au(1&F-MJwS3br0(#F%RrxOJR({p;nyq1 zk*jakT={Z+Km$9sgv-ZwLwcmHH-xp$&s#aA!ujQ*Vwy8)P}!U-83S=Ni~aRC>cqU0 z|M~j`@IIM6L7oI|iW>dys!b2%<=@hD@dAY2v{gM;u|9UOEyY)@lZ-9-!_~VTd7Z69 z(>J|{{YSAQ>?*kEzbKUS)<`NPur|QAF~Gn4i}Oim?B7NbH}!7XiRZ5`tF9Kik0GVD zLFBL}NZ;tTeAsgK*xjL0UC7a2>*MMVFl7}4z&2sVX%8*faas2dA-6iR`G58}PUFPc z3^8Y5;yPXlPElkc^c^2|oUgJhzQ?Ax-bwbFXIfRf)UMVQhP+twshi+b!M@qO4o0%$ ztw5kM&o~SOq_g~Yy46P8XdrxTc1>{Tzdbk&7=qcqhJDt5LEGzao&w(|cc;qe>mF?Y zaOdM`u4?SJsauey@WnG$OxmH>!u=NLuLDHcYuG;wXm{L{-4<<+b1TN}M^iFPC7p2V z(~CWk0y|$hEeHFy%z13atF0nyT7ZkS9%zBCFv78=^L<;D4tpUxAGh2)hnxPnGoIr; z`Q;w!->g(QFfEdfB58?#M>eysZVtTwKtHrQQI+Ntmjn4Sulnh^XD-9h$MNN_F?tJM zzUfe?c-w5Mh)D{EyTI_#1y0?4n-E2KdUW^+lieV3hV?wxYzZvNOV(xhD3#qYaD?|f zmv|v4Qksqi($*n)^Ug6S-O?tc^Q!%@gLN=lOTDdK!YaOIH7*-}<~1D#KXEz$DOPB6 z6!dPe;Qn0|l0cR>{eL!|X%}p{4d{UFew;>P+Mww?tTbHg_=LOk%T{)VsxDfy^wgSU z>;+u;r`CgR@#`*8OuTgTNFCR<ZQYi+#|!+1#rY&}1)Uj| z@M}HbVwd|dFM%lET>C>8AjNJkp>ah%xc20epNio^pR(cp%XchF9ssBQm0=&vGacjm z8PRHX`7s38_wSy#ULRbzTY6LkNyg$?9Hn#uo>cKi8}JPXmW0mpXa zS1v4n@vWckW<9HmXK(KzOovn15b`p2ykLkLsB_say;P;Us||y zNsv61FauQliT7FA*>Q}^asDoUDB*Hh&OLfmS;M|;>4Np5crCnVYv%mx`bP_{Yvkz0 zwpb7H)}KiH7242EZwAvK>@j}m-R@g`!I4YX;TU0--ymLN$hy;(;olva%39R-5C?R_ z1h^?^;CT%=CqUS)mW)=SHgBmg|6Q9_#^E@Ia|f9|%-aJ}At zoVS|r0pSvVoc{T9KciFM7mI62N2aW!>iy1M3tnIrb7<;)W@e{a{wzG7vg(q!0RGgY z>iDP<$3Ks;jLeXw%ev;afk{>`)4%seIIDO17DY)91i-`+o)fa1(JMGqTjFoUO7h#C zMYoB2(={Z^ptDsRtMy%szz?b;6~B*|c>4nq0M^2UXU_uu~`8wcg~u zN?zCChBlSz#-sc41GNFGwCbJbQLyOLifz1vy^1^NhS5quV*T4u6VK>;!T)ib--mGy zA2=AU2p|E?+L0^2{dG=^u3xUnVMyfGF7}dEQ|LoB<4MVe+^+t_-A@(Tty<)!V_N7m zFi+p@za=p)(s~^m{R$AofvHN|yy*3hP00(F-eR%;D7A%)I8&kr;svdyS^{2a1Pi|a zrYVP+L4RoS-H-rgh9Xde6m{b5=kyGa9m9|(GKRh~QVOdBgP0(IxwP+(_$h?5HJNeuko#(ELk_~%65?s zH$M|jhh<}c|57fD-ZprG`j9p2A02-aHQcQ<6M4gZ{g4(M3$Jd!g)}fGviXqeY4s4e zuX~21V?Q@osK~GwGG~(0zrOzlo1rvEura}_f<)mMyh5hD?xBCU@lYhB z#*Gm~3d5-xxT+g7@UW_qbjdPf)R2FXzl0EwY?FAQlMgaw)ENw2gmL(c_mzifAU%`= zVa{BzsZF8WxCim$)vzZXpz3Ku)abOtV4#2;!CzRuNG^wk&zexIM00Hcqu>W|!NN{S zctID?ksii~rpQ`}F%#&D_1Ot@j6@F@Qx-7?0{KTEFZFLHiCBop!-9ysLTE*kabVKu zykvq#l!ij8W(3fx>tcb>vSJX_5V9{IctYU52|-H0QDrG|_w;Fw)GFGOE$K z5lTT*AdFO)6Fo2`Z0;|q=fo$6hYQVSH=w?JZwv2DSf1B@s0o&0=G*Mv_r9( z{~jqSq~0PkTrDX>^8`o|2kby;5E7dur39!{lBH-8h@(F`GN~JoV}?FWCGQM80e;h% zp^an`W^53(J%A~!)R+=$7!C|lf>xSwZ8Z{5u7}1!ZW=Mx(TVh;fn0cU);zV786^dx+B8%;EhZ&vDJ3vP3%mQ0Fo@<$u zfHCwsES46mhcXTb3=Bz0cu*QJ5Huf(z79@ndyM1}#yqQ>^1hEW zrGFAgZ41T1I8zIlD|;C3Gwnr`bY*FPnfqu zF`pKs0l7AZp?(A(L<4ew9PPI)nF*veO-!Xd5K4fIU>%R}eGEtd6?6*q#=k4z_OrKFG_0+UhSaWDTMw@@?QX))f0OasqY7$^TPceX z4>YNNg&qa{q0ar(ofVgH`myx9=Ppr?=2x=|bmZ|LtALi#pg3193R)FSTQOSK?LK3x zcT_j}va=D=QBWbi}S}l0V#@p z+SG+4QY@5Mw#y4EA;-M$y=XyFRQ-o$@(5ALW+>!>xM#JZ+BU{xVkag5D$J(H+4;jlxUGDaXNTf4BCf7as8@~ZADy;GzdHpmfTe2nI}-# z%bhOg@7?v*ML{BTBZsp(7USEzY%Z)c9?eU=G#rX3}T)7v42a8 z8*Sw7|6UU9f27N<1ea)1-)@@+GChe2=%2}?4WU>=TX?K7qHdWzX-@3(!L)dc-LjSK zUu)Zbtv$2x&ao`wsj3*Cs#D=-;UA5^BB@iP`Ry>E0hn->KYfDm<5uLjps0rWg-eq^;V82mw;V1arT)Vtfb-k zN!(RuBenkz@cvcuis z?q+xM0*ZND1nm2uZ0B=#d$G3L|FZk~?t`t2URqYI1V&ohC~W(5rg%AKfdK7)SQ>@x z?sPLUmVLYxbUT?Oexf#6OZeBiKoP^#bKCO*H z+%}%?FD_pld~+$XUvDmR1|P^Z7l?fe#?I%Q*^Ihcz)^bTh{I=dzK_zcoV$zSr=Jk^ z$aQsfRJ}DVhsf6y_0&7oX-CrYk-V%fF9$ND1=>aF3lM4fedbG*>6_7ghD~-uf3w$LS3~ zMLx7^aN9!;0Ck-sM@MMyp@_5qD5N2nQq9{cUdRXWSDclyd;KZvy{j+|xIBmB>2MK}bt2LHJ3CY$#>rW`-!{!uj}y z4vz&wr`7j14xR@#`NBq!{I$W2c~Ql*YLPfBcskdVLkE{0P#ng&EL9L~mxr&nHM~JG zx@hSdzB$!3bwID?Ccl=SVPDeHid_|Qj?e4>k0)P7ClsjcQ533Gva$Cz26wnP6;N9i zk1=R}uLCvD>DM8oaymFtpe{s4A_Saa?-x+-@Lyvwe`TlaSq!U;8VV!^u(+&S9!3a) zn|w5RHX)5D$JB!%xVHOYlA{5^dTq>t^?dA9C@5AIq2>sJp;G|M(Khl9345q|Fg?h_ zCbc->co5?e5y^w?Z-`xB!KfykRgrf>ifpgAQm1A2@C#vd29KGjZM)#rP*^QT*6h+% zh9lJH$$QSY0>Sx0UKsvLBs zimRjf@=8J7IIokvcaz}^WncbfrwF24mB7nn*M|`a-!^Fv{Zmlp6QR$tn2=AJd4}uv zS;m~vni-p!<|XsamWlL>$d~7FF58R~^;YwXEg|~``4#i_ueu!8c#n?%^n*|45yq$b z-@qBR%Uml}dFgY=;3e~n=5bf+u?Qq_5v>?X-xX&_h@95AOF1;ab}okO>^QSI zpJUhd0I#!(38u}+2X&eEJMg(ao4p#Y1P3X+Wv|?VP@cFz=YG4Uy;Iu7YX-k-KUAF4 zcd+*sm-(k77P7Bij-9QsH293<`YNb?NpMF5Z6>rOVbCjUeBjX6=Tzkdu$U4GKPOMh zzE#MqpHzw1ziQ5@Kk?G(S75kRG(Aa^({J{%uSjh) zes%Pzv3XjbN2rNL$k`*%T)M5P0+9%pbe?XfgeqJ-`_E5@^!qi%fbk5+T~-Bj4|#5n z%1nt9-7j^Q7*0JK8XQb@1oN+P>?4@6Y(Obl9!lbC*+dgQKO46x>3%aHdk=;?*{QsU z0w#vlY!d=y4$V5b4W8IDs^Jdg%(I4{ueWvxq}uJ-34HM zw6wCTnK>s{XV!E+u*Aam)@jk=g>uxJtLLvZj)&YK)J;WIFW#PyhQ2WEy9Yu?t4AeI zF{~GAFH3Vj2ylwK8cf0tLu*KNg+VW+$cHQZAK?y>*SR?jii`Va4V2|x=B8#tZ;M~aOb!*<_(xY7Zc3PHeoE7gszoYqjZ|%!XZSAG zO!nS5w1b827Wlm?K3Fsb9X*G_nJ??S?zPyHEc0U&lO##X_O>O>7jeqpbbe3)J8DJo zd5XC1h%b9=j(h=isDYSz3xc#oTck?G-IA0d%W25ZsAlN}WDri(5xdt@#~X_aJ25Pm zE2t+&Exa}+8W%9-y zeI!Mzk$iyUu>!E5KXb)n0KvTfRkulRdc!)96&?QE?JdIV7+>53{38INSN(hCO6kd> zb$X^ksdU)m)SE9gjgRJ+&BRrW3E5Q0lX4SGkb!z65`3u+km=U55qdL1z5*II(59bt z^r!fsJo;ZrJ0bT_bdrg=mC3uSr;9@VYR!59Blh(lU_Jc_*p-03^zuo!K=euGySdJH zV5M3Wxjc;D_lTw!!?RlV7FOr>SKr)TkK$t9%@NiB zMvnc@&-*742{KOkZk-k<X%RN6H#3w)-3^R!9RVAIioUrvOaN$4-X z8ssACIX0rcTu&15Ij;C4 z*^i~3f@yXe1zoQD=KC&A$+bvSuDcG$>~G44;V?)ry<4hVRQB=uIGsW&Lcb8&7yWL=d^D_H%yMYrw|A?RUN@01i2gDPYWjG14Yo>_OP z?P|KNXFP8b=CZP-anx~b*G3;WgzXXnNjI6cUcujf@SpqFq=b}E0;nOY)Bp_dnq2`a zdhnSCl7Xw5nqRjorMMKGRpGT;ixr8VU!piY9PbW=y}>!}p?Lh4$JDyXi%+7ub_+TS zF%+*yPo5T%4mNt*C#^s4mm>lNo0w&aESEj0f-Tn6M6n??bLZ+V>U~dp;EKJH705zt zSHT^OLGsTPu$?j!p_dr=a?hm}l+bdtb|bKCcNEj9$xKPUWu@gs@}jm{nf_|{ zHg>k|W8!n9uw`y=+LN(nhTmmlu|}IvO55W~w>sxzGAXL2W6+uyoigl1s{_X#+Qk}r4@RaI<7&B!Sb<_@lgs=NWk*J>>}#ch+MaRn5K~?zx@!PC?CKc z-LQAvBX|%TG_n^YUC&2sS6dtEVI=8wAAm ztoVv38qfx^=bS}BL?X~^%daZ|k#e*dOO=WZxRi=Xz^a1sG6<7dsrUi|^4Kx6@>)VB zq_z>?l#!3z z^IW!{9T_5a-|Eo`zW?Ftz1%Es1UB(#u>4t(ao3_&DJ~9Q*rmsZnc&g6s;3~xY3*g% z?@fY$VF$mfa>i`zsMF-tM)+o{D_-3!$>uTX_BwgG>asB#cOw3-!Xc4$E%jCVvpB%k z9um4#$=<~9hi~rnel|BO+4zhrq$4#w(FYgCQnC3|69T*098xlUR8r&vVCTqGXc2LC zCc$B%MiApgVQ!fUI>#KgDf&z|sO6|rtv(<}eO@Pb@BR3v=SBu|d*Zt=YdD^|ivp+4! zACB>U8|ZZ9Y{QZap4uOdG&uF*-!EOma7}=05A40$n*kaRckryi=Xn2?YYR1i8vL2} zzs1@e6TpfdawZ@i+rEVF52^?!|2oxYy2hFBC5f+xNmsbl-D0pWd{Ijk=iQi9lXW0B zW82K>!cy$DlEQnlrJOPHyVGYep)akv=^{W$)n$pj)qV*(i(B4J{7#L7syOsTF@;H3 z$St&)PVSGQ`U$uyJu@cbOLzoxs;9Rr73i;Ritw2rr;d|Vzwu@``4IZU`bvqrj`~U3 z`XG3tnL;O{!kxdU^(j%f?NkCKP5)j$;XR+@R=pW#tv#PgCzZhi8SIW(xA;kME57VC zS`s5Ai)Gi|Xz)OUPwvhKhl(PPB>J7y0Olpv=1gyc#bU>N%q2e#cjK#?K`Nhq9;7T?%ZKMyq>(IcJ+ z)+7E{RG&lOuw)4}(3~Gjq0oV1Jb7S=(?TOpq1S9jhg*NNE=|8vRj87fx#fswfomJ3 z2BkB--n!i(+3W2C*8bkV&IZ_!d0GGva?bd!hNr)6v!aV{yx@2q*C%Nv0E^I}!--jp zR@REFgn!i~SLW44Zwc(2EzEZ|*81bd6s5Jg31o|RvE1tMNA%}REx-#$sH|{y8$9Wh zcJe$rtpJt7i>oA+pA8Jk$+dP^=FThH-0OxSbA(+dH*yU0pJeBTuP^3u>`B$!y}=Ac zV4P^-&D#~9b5Q(U|E4eTi`hn&XPq_>#8_N=%NNq_zR2-14bI4UL5)VUb;CtFdmtC$ zT@BgnHSp$+;Lxfu;Y0Lr*|s**)#6rxOkIS_c65P3Npu!qtDUBgDd0JpwqZ;kmWttBYw zv53I&=4tEnX~l^WS%veMdqCHb2=br{#+4@Clwu{-$-;(}=X_C>4>$i2Fa=Z2?@2Zdw2i|o^Z?k6q=Lj^Ar3_ zk$S+t)x`q+`#g(b0Z@VMiu~<#obf!Phb>{OF^vW8&#d#0^I#CY6Yr>dBV|1EW%$Cn zs{W$z?H6L=N(ySlOc}G_NTZTbxdDPR(8l6Q1=z2K;ez%%^BZ41o_Q8L4G%pGOoZ1` z*9=(H96$Q6(RYo(ZPv00a$fC!&n=&c+xtkSZR6@mQQwn#f4(!kH$ADh2xFo814%|YLj>4%Fk}j20K5?XSI7ub z%L;&nj55COik$xq-_uJPe_w*w5_i5xO#GjK&8E^!L0^2+zVNflEsq})=?vrlb5x|T z7jB*?iiE@DsW0?8-IHp#@olg_6dCuuv-Lm-;PkVBNeV>yo84A+M*i#(u(+`Nd&u^hW4u8eTHs=6PMMI3|#g7tnx?GlrEU3K*(KHXmr15K$aU(#s|9@&a5|k2T3%pG7R3+UGXU`$8!*!fO>gk`hWo8B?q#e_lgG^IQQnn9*&N-CP6y@h} zCmmQZvlS2&Ma@&32VvvEQVYn^ZP#`OQYw=PP1Jg_U_y3TaQZq^c6udKcFJ31?+o&$ z)j{{>LGXKqO=R!bd2v?ibWU&oWic_cepqGnvGlw|d16x$rR2PR7zrazho;I}B#pT~ zCKY>Z8Vx(kS(bClb*;>Hd{P59@x+1hLx;+U&PJ@Hz`DT2W$FZm$6C_AlAHquMk6C0P?>_?sx(DpCBFY?RWqH@>2r9 z4M~&u&mfy5;OQe2*T3MQ5M?<4D}+JrorHkrJIO9N00IGIy806ka%2YJg^))B_*)Fj z0S;L2u$5^KfFWec<3Dt4JOLV*5LQpXr~hGs0eOl7P`@K|^lRSV(u)SflgFb2Ay_p4 z8OUih0J-J;s|R5qdNuD9{(;j#)EWS65ax#eFz;yqIN|=Ax%LP^0LcCh&iN;NDj>k3 z>hax-MbY@1inA??0vQ(lRFs9F4&3+3|yKZKK zR0APAXeT6Y)fADu)yCIPBEp~j-o#HRFRB=grg@T4!PIYx%(=`aG zD(PIG=OpMep&m<8Z|yAz5bVIZq^8e6@sjW@snX4s9iHOFAcwHbSI$F3Ngd@@0NEUU0&W@O(N!h_l zF72-$aKT{=^rJj(V3kL-hDk#Yx>4x;40Vpc5}XM4M&uESPs^3MI)Kk~c8)H;J>3LI;w`!^2Hs?rs*;ks)YON~&6fOVCG^wh zt-{9+719{1K{McD3BBE+jta@`&8vgS1lMKY9lS9V>MMo{%!{!)8s5y(dduSqH{D5V z63O7YRwJsd7*d=vT&(Yi(<T zu4J7BwHj~3KAKP@Z$jd$?8xnrvOA0vS7i1X9;x}v^bOcUaOHvb(aW3j@pil9-da+& zcD?j|p}}J5?!wuTM|YM#^sOgJJmP~2G3x1=@(cB@{iI{+y1`sxpc5uD?^b`sMgA6( z2RHFte~HJ-tEU5RwqfWi`!m#UtsFNG-YEadp_LyLP-n-Ho5t?Eoqq~2WRH}0O|6P* zI=WFSMxMaR{93`kI!iUF9x&4yWH98*lbl!8Mv{hG%SV)?)dy09(niuT%ev}+)uvob zJ5|pjR=}nd&N1#a#qmRa@D(uLj?8_s-C zdkwSQiK=K1eG%oricHsEk|< z+6t?CP%mW87lEJ#p(E<v^atAM>g$u)rLRIC49e1`>JWONQYenXdrsr;Wq`01ue2X zZBqn&%AA2Ho2*o*ft+%eh7Eq!ps7U>^4u!Q{*}7E`91VMm$4EK2;NSmnqi<1d4Eg6 z=oq!TaL6(W=pq!w6IWKzC24JS_z#y#pailk3>|sFqOh`83s(Q?IoHm z%B_Eq3RWLnuwR<&_ar6tVs2!W(MdnB3g(+sEy2(#MeiIvHZ%k_tw+Rs6oV-lb4k_e zBi>*k2qo&uUqwPo)cSk0@;6fj<;Q^m&5v zK((NHy)f@81ry14$+z}(;7{T;WMl_bh`z_8mVwLXxYinU6?S z?}lG|^j~VTb0!BgXxr|q!pi-?y_44|s@{KFYSduc>+jSHcv5q))RU@nzk05#4daj+ z%@OE>lw@@~s|WEm8pgUe@NxzV`rXhuS!bQfVcib6mios<&+rU+Q+048OGO6u;1eT9 zwTHImcF&EO1-{!WO`YU@OOxBX$<}@4ZM|*TxR+>BbbFTCn!B%;xa1N7YpjP^Mkg%x zG1=8LA7no@w10X!J=)sc@#gDM$F8a)s+~rckSkkuYZVj9@=cE-*Spd=XBk_ZNO6-K zw5SoTtejRHPHF7MtvDUV-7t@|UEEqD)bWmFGLL4G@-swU=ZKdLXWC?2`c3c?SEo|f zByvu0@pteBglUsm2Lx^gXZrGbTLe0`QmI@rjqpNHNkY<7z2Isp-717u z+ee01+`y&VZc!2Us>(dxk$r|WXqKoQ$7!Fy*$8A( zNQgkmP?bi@lS#;u?q6|Lh7#|_el(tNP!5kxQ*G;6_$#fu9iAu%cK;2v0il;!+m$(- zOn&QnySlm1V(1n8s_gJBkZwYNwrprNO;u^Au`~crc2#(YhWVom{pNJy$Sr#F;?^~v zjtyF~4eZ%Cj#DUu#O>b5aA-qsZ(uUhy=jWz~|sddsWG zob7&BXruNh(`Z8QEuu|b>~Ko;dDC#c{_>+xkuALU*=+qYc(_U)_X-@h3ucL3@ABh4 zD^5H}EXMt*wek2g*FxT>Q*T+-QiPje<ZUr@Us<1&UqL=6WGi2n)Jxt(;uy`EKw9pp_xVMHjD+fRGRF} z;|GJ;7U688`o*FKO>IKy7S~O*Fj9aHZ{tmj^;0D#^wIF0i_kEv=z*;GqP4&fWBkXd z*v&;GN> zVOoob4R!2)4XZV~A>*BG-)j<$#qszR=jg%DOV=L8$!a{&*um}UFNTlRQT9}Bz25P_ zpY4)adpQis4ZSPGuRQUWuII5alr zB$|xbX5*B|eGSHS!@*l+>nE!VDsI!dtu%Lnl-Z9r#dQ7pTQAiQiFdeXisKqblf@-3jr z{Wwcc*}Ake`#oaTamxXoJH571wk>ym6V>OMzx((x5n{kLdv<#3K$Eeezcd0V1^VI1_)ay- z;Z_lxt&l!X`tczdA{qxYopf^n6K$#0?G3prfel(x7aTdVyB;IGT9DeepFM znr-ZKvROR`dftyN_L&l>;%nsK5)(>!onOxxu+>CaRo|uV|W+X*#lbcaFhAf z#gKEe4nI5xE)5;OVUC(O7sVr)EBaO>pC75OoZiG6xf(8e-ieipUIODpjvo$%1R$AV zSKotn%GOQXQa)hcY5+YLA22Dm1bbYcTPzc_-vVmkj$9J(Hkya ztdi*t(d-!Z@6<2ax{?L#G8SK%Ja7+fJRqwWH+nTR8pb-a8-skSU)T{`;8&zb{0pqO z;!EOKHoZ7bzJd!_Oa$$~0}Q3@`?#~6r-b^0Rf|E~=RVa-ge$qP1&bjo4)8vVhu|o* zA+AH==&YTOmAMabmF=g7L^3~-h4Tqw+OT}(^g;7)RP9#IHwWdbqVr8$A48|l`V}oD zwlvdyOob=%mK5hXi{5Ne<6MA;Z3_9qVWH>LK5P%Ht=KNa^7+DGP<9xWr4SH)%XIcl z6~!GpcGID*po`l{Uqc<{F#UH^1Ch1T!i3E1P5u=a=Wwh>GV6+Oav^`>Th=h2m&?F> z-h^V7KOeix=}FJ{57?Ici5%M>#4gSID+?a^PNEw>gup%vkG?lqr{X?=kMq}^L_L9} zlPWoH7`_eH3p*TOlK$;duYO=hn7n&d!*%p3`ctIS-#fMsg2pt84!&w9w+3y+s_n(= z4)Wlg^oK>xBgKV@rfS}nah&}A30aQTqD65|>K2zv7V6LlJ>Tgap1P<0G$Lx(ex*dL z%#IDyoW+^5j7+NAC@AWue*N=bJE+DiL}rdZ7LQKTGO1l@ZCi({`s~6ucxQ&^s3pUE tjDv==GQAgfr1pkY+cr*DqEl{!BkudMA@j=sG9)f`b|fHBTu}n){{cMQTO9xZ diff --git a/build-doc/weather_station_article.md b/build-doc/weather_station_article.md new file mode 100644 index 0000000..b1ea089 --- /dev/null +++ b/build-doc/weather_station_article.md @@ -0,0 +1,57 @@ +--- +title: APRS weerstation +subtitle: met hamnet verbinding +author: M.T. Konstapel +date: 2024-02-03 +website: https://meezenest.nl/mees/ +page_back: https://meezenest.nl/mees/weather_station.html +logo: ./images/mees_logo.svg +pdf_version: ./weather_station_article.pdf +git_repo: https://git.meezenest.nl/marcel/weather_station +numbersections: true +# Formatting: +geometry: "a4paper, left=2.0cm, right=2.0cm, top=1.9cm, bottom=2.54cm" +abstract: > + Ik maak veel gebruik van het APRS netwerk: positiebepaling, telemetry en berichten versturen; ik doe het allemaal. Dit kan omdat ik dicht bij de Duitse grens woon: anders dan in Nederland waar het APRS netwerk dankzij lastige regelgeving nagenoeg is verdwenen, is in Duitsland het netwerk nog springlevend. Ik maak gebruik van Duitse digipeaters en iGates, die gewoon berichten vanaf het internet mogen doorzenden. Wat een geluk! Het enige wat ik nog niet kon, was weergegevens delen via het netwerk. Om daar verandering in te brengen heb ik een weerstation ontworpen dat elke 10 minuten een weerbericht kan uitzenden via het APRS netwerk. En omdat het systeem zo'n 100 meter van mijn huis in de acchtertuin staat, heb ik er ook een 5 GHz hamnet verbinding naar toe gemaakt, zodat ik het systeem op afstand kan bedienen. Oh, en omdat twee beter is dan een heb ik er ook een 20KB/s hamnet link over 70cm LoRa als backup in geknutseld. Het hamnet gebruik ik ook om de weermetingen naar mijn Grafana dashboard te sturen. +--- + +# Weerstation + +Als uitgangspunt van het weerstation gebruik ik de SparkFun Weather Meter. Dit is een kit met drie sensors: een windvaan, een anemometer en een regenmeter. Deze kit heb ik aangevuld met sensors voor temperatuur, luchtdruk en luctvochtigheid. Al deze sensors zijn rechtstreeks aangesloten op een Arduino Mini Pro. Ik heb daar een RS-485 driverchip en een ompoolbeveiliging aan toegevoegd. Het uiteindelijke schema is hieronder te zien. Ingewikkeld is de hardware niet, want alle fuctionaliteit zit in de software. + +Het weerstation is uit te lezen via een ModBus interface. Dit is een industriestandaard, dus er zijn legio mogelijkheden om met het weerstation te communiceren. De ModBus registers bevatten de meetwaarden van de sensors en worden elke twee seconde ververst. Dit bepaald dus de maximale uitleesfrequentie. De volgende gegevens zijn beschikbaar: + +- Windrichting in graden +- Gemiddelde wind snelheid van de laatste 10 minuten in m/s +- Maximale windstoot van de laatste 10 minuten in m/s +- Hoeveelheid regen in het afgelopen uur in mm +- Hoeveelheid regen in de afgelopen 24 uur in mm +- Temperatuur in graden C +- Luchtvochtigheid in % +- Luchtdruk in hPa + +Daarnaast zijn er nog een aantal statusregisters beschikbaar. Deze worden besproken in de uitgebreide bouwbeschrijving die beschikbaar is op mijn website. + +De Luchtvochtigheidssensor kan bij een hoge Luchtvochtigheid verzadigd raken en zo blijven steken op 100%. Om dit te voorkomen is het mogelijk om de sensor automatisch te laten verwarmen wanneer de luchtvochtigheid langer dan een uur boven de 96% is. De verwarming wordt dan elke 20 minuten voor 5 minuten aangezet. In de 15 minuten die overblijven koelt de sensor weer af tot de omgevingstemperatuur. Dit proces wordt heraald totdat de sensor weer een waarde beneden de 96% aangeeft. Tijdens het opwarmen en afkoelen kan de luchtvochtigheid en temperatuur maar eens in de 20 minuten worden gemeten. Dit is de prijs die betaald moet worden wanneer we een goedkope luchtvochtigheidssensor gebruiken. + +# APRS iGate + +Om de weermetingen te kunnen uitzenden via het APRS netwerk is er een 2 meter FM zender en een 1200baud modem nodig. En een computer om de gegevens via de ModBus uit het weerstation te lezen en door te sturen naar het modem. Een Raspberry Pi Zero 2W is daar perfect geschikt voor. Deze is goedkoop, klein en verbruikt weinig energie. Omdat een APRS weerstation ook zijn positie en tijd moet doorgeven om op de kaart gezet te kunnen worden gezet is er een GPS module via USB aangesloten op de Raspberry Pi. Strikt genomen is de tijd niet noodzakelijk en omdat het station vast is opgesteld kan de positie ook handmatig worden ingesteld. Een eenvoudig Python programma leest het weerstation uit, vraagt de positie en de tijd van de gps ontvanger op en construeerd het APRS frame dat uitgezonden moet worden. Dit frame wordt vervolgens via de AX.25 stack naar het modem gestuurd. + +Omdat APRS over LoRa op de 70cm band steeds poulairder wordt heb ik ook een LoRa module op de Raspberry Pi aangeloten. Het weerbericht kan zo ook via LoRa worden uitgezonden. Met een diplexer worden de signalen van beide zenders samengevoegd en gaan zo naar een dualband antene. De software hiervoor is een in Python geschreven KISS interface. Via deze software kan de LoRa module gekoppeld worden aan de AX.25 stack. De Raspberry Pi ziet het modem als elk ander KISS compatible modem. + +# HamNet + +Het syteem kan autonoom werken, maar het is handig (en noodzakelijk) om het systeem van afstand te kunnen bedienen en wanneer dat nodig is ook uit te kunnen schakelen. Daarvoor heb ik een 5GHz HamLink tussen het huis en de Raspberry Pi aangelegt. Op deze manier heb ik een snelle netwerkverbinding naar het weerstation en kan ik via telnet inloggen en het systeem bedienen. De HamNet link maakt gebruik van commercieel verkrijgbare schotels. Ik gebruik apparatuur van Unifi Ubiquiti, maar apparatuur van Mikrotik is even goed geschikt. Deze verbindig wordt ook gebruikt om verbindig te maken met et APRS-IS netwerk op het internet. Zo doet mijn weerstation ook dienst als RX-only iGate voor zowel traditioneel APRS als LoRa APRS. + +De snelle netwerkverbinding is handog, maar wanneer het systeem autonoom werkt is het wel een beetje een overkill, want de verbinding wordt dan enkel gebruikt om APRS berichten door te sturen naar het APRS-IS netwerk. Daarom heb ik ook nog een lage snelheid netwerkverbinding geintegreerd. Deze heeft een doorvoersnelheid van iets meer dan 20KB/s, wat genoeg is voor de toepassing. Het is zelfs mogelijk om daarnaast ook nog in te loggen via telnet. Dat gaat dan wat trager, maar als backup is het prima geschikt. Zo heb ik twee manieren om het systeem van afstand te beheren. De verbinding gaat over LoRa via de 70cm band. Hiervoor gebruik ik een kant en klaar board, een LilyGO TTGO T3 LoRa32 433MHz V1.6.1 ESP32. Hierom heb ik firmware van unsigned.io gezet. Met de bijbehorende Linux software (tncattach) wordt dit een netwerkinterface onder Linux waarover ik het netwerkverkeer kan leiden. + +![SparkFun Weather Meter](./images/SparkFun-Weather_Meter.jpg "SparkFun Weather Meter") + +# Verantwoording + +Copyright (C) 2023, 2024 M.T. Konstapel - PE1RXF + +[https://meezenest.nl/mees/](https://meezenest.nl/mees/) + +This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License. diff --git a/firmware/weather_station.ino b/firmware/weather_station.ino index 2e82ae5..5cbaf0b 100644 --- a/firmware/weather_station.ino +++ b/firmware/weather_station.ino @@ -191,9 +191,9 @@ char HeaterSi7021 (float humidity) } break; - // Heater is now on, let the sensor cook for 5 minutes + // Heater is now on, let the sensor cook for 10 minutes case 2: - if ( (millis() - StatemachineTimer) >= 300000 ) { + if ( (millis() - StatemachineTimer) >= 600000 ) { StatemachineTimer = millis(); Heater = 0; state = 3; @@ -202,9 +202,9 @@ char HeaterSi7021 (float humidity) } TempValid = 0; break; - // Heater is now off, let the sensor cool for 15 minutes + // Heater is now off, let the sensor cool for 10 minutes case 3: - if ( (millis() - StatemachineTimer) >= 900000 ) { + if ( (millis() - StatemachineTimer) >= 600000 ) { TempValid = 1; // Sensor cooled, so we can take a valid temperature reading if (humidity >= 95) { // Humidity still above 95%, repeat heating/cooling