New
1
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
public
|
||||
release.sh
|
||||
newContent
|
||||
|
|
|
@ -1,14 +1,35 @@
|
|||
---
|
||||
title: "MQTT at Home"
|
||||
date: 2020-10-28T21:32:53+02:00
|
||||
draft: true
|
||||
date: 2020-11-26T21:32:53+02:00
|
||||
draft: false
|
||||
description: "How I use MQTT at Home to connect stuff."
|
||||
tags: ["MQTT", "IoT", "Blog"]
|
||||
tags: ["MQTT", "IoT", "Blog", "Go"]
|
||||
categories: ["Programming"]
|
||||
startpage: true
|
||||
lang: gb
|
||||
---
|
||||
Ok i live in a small appartment, but at least I have three Window and a little bit stuff to connect with each other. I startes with [Ikea TRÅDFRI](https://www.ikea.com/de/de/cat/ikea-home-smart-beleuchtung-36812/) and some selfe made components based Arudino/Wemos. About one year ago I tried [zigbee2mqtt](https://www.zigbee2mqtt.io/) to connect the ikea bulbs to MQTT without using my own buggy code. I used a MQTT-Broker on a Virtual Server somewhere in the internet and develop some PHP-Application with lumen (some of them running in kubernetes) to connect everything.
|
||||
|
||||
After some issues with my Internet Provider I beginn with a easyer and locale alternative. I already used a Raspberry Pi for zigbee2mqtt so i want to run everything on it. On the other hand I want a secound MQTT Server in the Internet(tm) to connect from other networks. Also I like the idear of smaller "services" managed single features.
|
||||
|
||||
I still use [Mqtt Dash](https://play.google.com/store/apps/details?id=net.routix.mqttdash&hl=de&gl=US) at my Android Device do control most things.
|
||||
## Basic Setup
|
||||
|
||||
First i setup [supervisord](http://supervisord.org/) on the pi to managed all scripts. I develope the new Services in golang, so first i build a small wrapper arround [paho.mqtt.golang](https://github.com/eclipse/paho.mqtt.golang), so all Services has the same configure also for the Last Will and Testament. It connected without crdentials to a mqtt server running on the same pi (localhost). Than i could start creating single services. One react to all incomming MQTT-Message if a button is pressed and change the light-modus. The light-modus are topics with retained messages. Another services subscribed to this topic and send the mqtt messages to zigbee2mqtt which changed the light bulbs.
|
||||
|
||||
|
||||
## MQTT Bridge
|
||||
|
||||
For all topics contained a state like the light-modus i created a set topic. The light modus for the "main" room could be `light-modus/main`, to change it i published a message to `light-modus/main/set`. I used another service just mirrow the incomming messages at the set topic (not retained) and send it to the original topic (as retained messages).
|
||||
|
||||
The [Mosquito MQTT Broker](https://mosquitto.org/) has a feature to setup a bridge between two MQTT Server. So i setup another instanc of it at a VM in the internet. After that i can configure on the MQTT Broker on my locale pi to connect to the remote mqtt server. I relay messages from status topics (like light-modus), sensor and device informations (from zigbee2mqtt) and subscripe to some */set topics. With this setup everything works fine without internet in my apparment. But as long as the internet connection is avalible I can publish messages to the online mqtt server which would be recived locale.
|
||||
|
||||
## Automation
|
||||
|
||||
All Automation Services are also written in go, and had a feature toggle as retained mqtt topic (with a seperate /set topic). With this I can change the behavior of it. For example i had a service checking if I'm currenlty in im appartment and the value of the lumex sensor falls below a special value. If that happends it will turn on the light. But I dont always want that to happend to I can toggle this feature.
|
||||
|
||||
Also all status information are avalible as retained messages at the MQTT-Broker. So each service can restart without any issues.
|
||||
|
||||
## Interface
|
||||
|
||||
|
||||
I still use [Mqtt Dash](https://play.google.com/store/apps/details?id=net.routix.mqttdash&hl=de&gl=US) at my Android Device do control most things. Some information like the room temperature are already stored in a graphite database to have access via [grafana](https://grafana.com/). In the feature I want to create some status dashboard based on the last will of the service and some zigbee2mqtt messages. Also maybe a webpage connecting to the broker to controll the light with a tablet.
|
16
content/posts/2020-11-30-Herbst-Spaziergang.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
title: "Herbstspaziergang"
|
||||
date: 2020-11-30T16:31:55+02:00
|
||||
draft: false
|
||||
categories: ["Images"]
|
||||
description: "Image Gallery"
|
||||
tags: [""]
|
||||
startpage: false
|
||||
lang: img
|
||||
gallery: "/img/2020/11/herbst-spaziergang/DSC07221_1.jpg"
|
||||
---
|
||||
# Gallery
|
||||
{{< gallery dir="img/2020/11/herbst-spaziergang" caption-position="none" caption-effect="fade" />}} {{< load-photoswipe >}}
|
||||
|
||||
# GPS Track
|
||||
{{< gpx gpx="/img/2020/11/herbst-spaziergang/track.gpx" >}}
|
28
layouts/shortcodes/gpx.html
Normal file
|
@ -0,0 +1,28 @@
|
|||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.css" />
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-gpx/1.4.0/gpx.min.js"></script>
|
||||
|
||||
|
||||
<div id="mymap" class="mymap" style="min-height: 500px;"></div>
|
||||
<style type="text/css">
|
||||
.mymap img {
|
||||
border: 0px;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var map = L.map('mymap');
|
||||
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
attribution: 'Map data © <a href="http://www.osm.org">OpenStreetMap</a>'
|
||||
}).addTo(map);
|
||||
var gpx = '{{ .Get "gpx" }}'; // URL to your GPX file or the GPX itself
|
||||
new L.GPX(gpx, {
|
||||
marker_options: {
|
||||
startIconUrl: '/img/general/pin-icon-start.png',
|
||||
endIconUrl: '/img/general/pin-icon-end.png',
|
||||
shadowUrl: '/img/general/pin-shadow.png'
|
||||
},
|
||||
async: true
|
||||
}).on('loaded', function(e) {
|
||||
map.fitBounds(e.target.getBounds());
|
||||
}).addTo(map);
|
||||
</script>
|
BIN
static/img/2020/11/herbst-spaziergang/DSC07003.jpg
Executable file
After Width: | Height: | Size: 6.5 MiB |
BIN
static/img/2020/11/herbst-spaziergang/DSC07008.jpg
Executable file
After Width: | Height: | Size: 5.7 MiB |
BIN
static/img/2020/11/herbst-spaziergang/DSC07016_1.jpg
Executable file
After Width: | Height: | Size: 8.9 MiB |
BIN
static/img/2020/11/herbst-spaziergang/DSC07019.jpg
Executable file
After Width: | Height: | Size: 9.9 MiB |
BIN
static/img/2020/11/herbst-spaziergang/DSC07024.jpg
Executable file
After Width: | Height: | Size: 5.3 MiB |
BIN
static/img/2020/11/herbst-spaziergang/DSC07026.jpg
Executable file
After Width: | Height: | Size: 8 MiB |
BIN
static/img/2020/11/herbst-spaziergang/DSC07045.jpg
Executable file
After Width: | Height: | Size: 4.1 MiB |
BIN
static/img/2020/11/herbst-spaziergang/DSC07060.jpg
Executable file
After Width: | Height: | Size: 7.9 MiB |
BIN
static/img/2020/11/herbst-spaziergang/DSC07069.jpg
Executable file
After Width: | Height: | Size: 11 MiB |
BIN
static/img/2020/11/herbst-spaziergang/DSC07082_1.jpg
Executable file
After Width: | Height: | Size: 4.9 MiB |
BIN
static/img/2020/11/herbst-spaziergang/DSC07102.jpg
Executable file
After Width: | Height: | Size: 6.7 MiB |
BIN
static/img/2020/11/herbst-spaziergang/DSC07105.jpg
Executable file
After Width: | Height: | Size: 12 MiB |
BIN
static/img/2020/11/herbst-spaziergang/DSC07109.jpg
Executable file
After Width: | Height: | Size: 13 MiB |
BIN
static/img/2020/11/herbst-spaziergang/DSC07167.jpg
Executable file
After Width: | Height: | Size: 6.6 MiB |
BIN
static/img/2020/11/herbst-spaziergang/DSC07211.jpg
Executable file
After Width: | Height: | Size: 4.6 MiB |
BIN
static/img/2020/11/herbst-spaziergang/DSC07221_1.jpg
Executable file
After Width: | Height: | Size: 4.6 MiB |
BIN
static/img/2020/11/herbst-spaziergang/DSC07231.jpg
Executable file
After Width: | Height: | Size: 1.5 MiB |
BIN
static/img/2020/11/herbst-spaziergang/DSC07242_1.jpg
Executable file
After Width: | Height: | Size: 3.9 MiB |
6537
static/img/2020/11/herbst-spaziergang/track.gpx
Normal file
BIN
static/img/general/pin-icon-end.png
Normal file
After Width: | Height: | Size: 960 B |
BIN
static/img/general/pin-icon-start.png
Normal file
After Width: | Height: | Size: 971 B |
BIN
static/img/general/pin-icon-wpt.png
Normal file
After Width: | Height: | Size: 660 B |
BIN
static/img/general/pin-shadow.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
static/img/general/ssp.jpg
Normal file
After Width: | Height: | Size: 1.7 MiB |
BIN
static/img/general/ssp2.jpg
Normal file
After Width: | Height: | Size: 1.5 MiB |
BIN
static/img/general/ssp3.jpg
Normal file
After Width: | Height: | Size: 803 KiB |
|
@ -12,10 +12,44 @@
|
|||
{{- if isset .Site.Params "subtitle" -}}
|
||||
<p>{{ .Site.Params.Subtitle | markdownify }}</p>
|
||||
{{- end -}}
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<img src="/img/general/ssp3.jpg" style="max-width:100%;">
|
||||
|
||||
|
||||
<h1>Blog</h1>
|
||||
<ul class="posts">
|
||||
{{ $pages := where (where .Site.RegularPages "Type" "in" .Site.Params.mainSections) ".Params.startpage" "==" true }}
|
||||
{{ $paginator := .Paginate (where $pages "Params.hidden" "ne" true) }}
|
||||
{{ range $paginator.Pages }}
|
||||
{{- if (not (in (.Site.Params.excludedTypes | default (slice "page")) .Type)) -}}
|
||||
<li class="post">
|
||||
<a href="{{ .RelPermalink }}">{{.Title}}</a>
|
||||
<span class="meta">
|
||||
{{ dateFormat "Jan 2, 2006" .Date }} {{ if .Draft }} <span class="draft-label">DRAFT</span> {{ end }}
|
||||
</span>
|
||||
|
||||
</li>
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
</ul>
|
||||
<h1>Bilder</h1>
|
||||
<ul class="posts">
|
||||
{{ $pages2 := where (where .Site.RegularPages "Type" "in" .Site.Params.mainSections) ".Params.gallery" "!=" nil }}
|
||||
{{ range first 3 $pages2 }}
|
||||
|
||||
<li class="post">
|
||||
<a href="{{ .RelPermalink }}">{{.Title}}</a>
|
||||
<span class="meta">
|
||||
{{ dateFormat "Jan 2, 2006" .Date }} {{ if .Draft }} <span class="draft-label">DRAFT</span> {{ end }}
|
||||
</span>
|
||||
|
||||
</li>
|
||||
|
||||
{{- end -}}
|
||||
</ul>
|
||||
<!--<h1>Blog</h1>
|
||||
{{ $pages := where (where .Site.RegularPages "Type" "in" .Site.Params.mainSections) ".Params.startpage" "==" true }}
|
||||
{{ $paginator := .Paginate (where $pages "Params.hidden" "ne" true) }}
|
||||
{{ range $paginator.Pages }}
|
||||
|
@ -31,7 +65,7 @@
|
|||
</div>
|
||||
<a href="{{ .RelPermalink }}">Read more ⟶</a>
|
||||
</section>
|
||||
{{ end }}
|
||||
{{ end }}!-->
|
||||
{{ template "partials/paginator.html" . }}
|
||||
</main>
|
||||
{{ partial "footer.html" . }}
|
||||
|
|