diff --git a/content/posts/birdnet_homeassistant.md b/content/posts/birdnet_homeassistant.md
index 31d338d..e7fd833 100644
--- a/content/posts/birdnet_homeassistant.md
+++ b/content/posts/birdnet_homeassistant.md
@@ -1,11 +1,11 @@
---
title: 'Creating a BirdNetPi Dashboard in HomeAssistant - Part 1'
-date: 2023-09-25T12:51:55-04:00
+date: 2023-09-30T11:21:55-04:00
tags: ["homeassistant", "python", "diy"]
author: "Me"
showToc: true
TocOpen: false
-draft: true
+draft: false
hidemeta: false
description: 'Learn how to take BirdNET-Pi Detections to create and display entities in HomeAssistant.'
disableHLJS: true # to disable highlightjs
diff --git a/content/posts/birdnet_homeassistant_part2.md b/content/posts/birdnet_homeassistant_part2.md
new file mode 100644
index 0000000..0d298ad
--- /dev/null
+++ b/content/posts/birdnet_homeassistant_part2.md
@@ -0,0 +1,537 @@
+---
+title: 'BirdNET-PI & HomeAssistant: Part 2'
+date: 2023-10-04T10:35:23-04:00
+tags: ["homeassistant", "diy", "selfhosted"]
+categories: ["Tutorial"]
+author: "Me"
+showToc: true
+TocOpen: false
+draft: false
+hidemeta: false
+description: 'A Follow up from the previous post, this tutorial takes all the sensors we created and loads them into a beautiful dashboard!'
+disableHLJS: true
+disableShare: false
+disableHLJS: false
+hideSummary: false
+searchHidden: true
+ShowReadingTime: true
+ShowBreadCrumbs: true
+ShowPostNavLinks: true
+ShowWordCount: true
+ShowRssButtonInSectionTermList: true
+UseHugoToc: true
+ShowBreadCrumbs: true
+cover:
+ image: "birdnet-homeassistant-part2.png"
+ alt: "Part 2 of my foray into HomeAssistant dashboard featuring BirdNET-Pi Sensors"
+ caption: "Part 2 of my foray into HomeAssistant dashboard featuring BirdNET-Pi Sensors"
+ relative: false
+ hidden: true
+---
+
+## Checking for Entities
+
+If you're following up on this from [my first post]({{< ref "posts/birdnet_homeassistant.md" >}}), you've already added your AppDaemon script and confirmed that the AppDaemon logs don't show any errors. Now is the true test if it's working: do you have the
+new sensors in HomeAssistant?!
+
+{{< box info >}}
+The best way to do this is by just type `e` from any screen in the HomeAssistant UI! That will bring up a list of entities.
+Start typing "bird" or "birdnet" and you should see the new entities listed there.
+{{< /box >}}
+
+## Dashboard Overview & Dependencies
+
+Now that we have the correct entities, lets take a look at what we're working with. Full disclosure that once I got this
+working, I haven't really revisited it, refactored it, or made any improvements. I'm sure you'll find ways to use less YAML,
+but I wanted to get this out there sooner than later!
+
+
+
+I've include the code for all the cards at the bottom of this post. You can find them [here]{{< ref
+"birdnet_homeassistant_part2.md#dashboard-yaml" >}}. This dashboard is pretty simple, it brings in almost all of the sensors
+we created in the first post and organizes them in an as-pleasant-as-possible view. I'm definitely not a designer, so some of
+the colors could be worked on...
+
+Sensors in the dashboard:
+
+* [Overview Card:]({{< ref "birdnet_homeassistant_part2#overview-card">}})
+ * sensor.bird_common_name (only used to generate the picture)
+ * camera.birdnet_flickr
+ * sensor.bird_common_name
+ * sensor.bird_science_name
+* Data Card:
+ * sensor.bird_time_seen
+ * sensor.bird_confidence
+ * sensor.bird_last_seen
+* Weather Card:
+ * weather.pirateweather
+* Description Card:
+ * sensor.birdnet_wiki
+
+There are also two HomeAssistant dashboard dependencies that you'll need for this dashboard:
+
+* [Custom Weather Card](https://github.com/bramkragten/weather-card)
+* [Custom Button Card](https://github.com/custom-cards/button-card)
+* [Custom Card Mod](https://github.com/thomasloven/lovelace-card-mod)
+
+Now that we've got that squared away, let's jump into each card.
+
+## Overview Card
+
+
+
+You'll notice from the few dependencies listed above, that I use this button card. **A lot.**
+[RomRider](https://github.com/RomRider) did a fantastic job of adding in a ton of flexibility into the card. For the overview
+card, we're taking one of the entities, in this case, `bird_common_name` and attaching the Flickr picture/sensor to it. Then,
+on the right, I'm displaying the name and common name. Here's the overview card's yaml.
+
+The tricky or tedious part of this card is making sure most of the card's attributes (icon, name, state, label) are set to
+false. Another option for the Common and Scientific name on the right is to use a markdown card. I couldn't get the
+formatting just right when using that card and some grid-card tricks, so I opted to reuse the super flexible button-card.
+
+Pay attention to the styles for the image (lines 24-40). Those are what keep the border around the image along with the image
+a certain height and width so that it looks proportional on the page.
+
+One additional thing I have been toying with but hadn't finalized was messing with `[img_cell][border]`. By adding some
+javascript in that section (see other cards), you could change the color of the border based on another parameter. Perhaps
+you look at the state of `sensor.bird_common_name` and if there is the name of a color in there, that's the border's color.
+Feel free to get crazy and creative with this!
+
+{{< details "Overview Card YAML" >}}
+
+```yaml
+type: horizontal-stack
+cards:
+ - type: custom:button-card
+ entity: sensor.bird_common_name
+ triggers_update: all
+ show_name: false
+ show_icon: false
+ show_state: false
+ show_label: false
+ styles:
+ card:
+ - background: transparent
+ - border: none
+ - width: 215px
+ - height: 175px
+ custom_fields:
+ picture:
+ card:
+ type: custom:button-card
+ entity: camera.birdnet_flickr
+ show_entity_picture: true
+ show_name: false
+ show_icon: false
+ styles:
+ card:
+ - height: 100%
+ - width: 100%
+ - padding: 0px 15px 0px 15px
+ - border-radius: 3px 3px 15px 3px
+ - border: none
+ - background: transparent
+ - overflow: visible
+ img_cell:
+ - width: 180px
+ - height: 160px
+ - border-radius: 69%
+ - border: 3px solid grey
+ entity_picture:
+ - width: 215px
+ - height: 100%
+ - type: vertical-stack
+ cards:
+ - type: custom:button-card
+ entity: sensor.bird_common_name
+ show_entity_picture: true
+ show_state: true
+ show_name: false
+ show_icon: false
+ styles:
+ card:
+ - background: transparent
+ - border: none
+ - margin-top: 35px
+ - font-size: 25px
+ - width: auto
+ - type: custom:button-card
+ entity: sensor.bird_science_name
+ show_entity_picture: true
+ show_state: true
+ show_name: false
+ show_icon: false
+ styles:
+ card:
+ - background: transparent
+ - border: black
+ - width: auto
+```
+
+{{< /details>}}
+
+## Data Card
+
+
+
+This card is fairly straight forward in that it's showing 3 key data points: the time of detection, detection confidence,
+how long ago it was seen. This could be fairly redundant since we already have the time of detection, but when you're just
+quickly glancing at the dashboard, minutes ago is much faster brain processing than comparing the timestamp and the current
+time.
+
+You've likely picked up by now that in the previous post, we never sent a payload to create the `sensor.bird_last_seen`
+entity. Here's how you can do it.
+
+### Creating Bird Last Seen Entity
+
+When I first set out to create this sensor, I was messing with jinja templates for timestamp, datetime, strptime, and more.
+Here are a few code blocks I saved in my notes in case I went too far down the wrong path. Here are a few of them.
+
+```jinja
+{{ now() - state_attr(sensor.bird_time_seen, 'last_triggered') > timedelta(hours=24) }}
+```
+
+or:
+
+```jinja
+{% set bird = strptime(states('sensor.bird_time_seen'), "%H:%M:%S") %}
+{{ relative_time(bird) }}
+```
+
+The thing is, HomeAssistant has already implemented this really neat feature for calculating time, especially from when
+something was last updated. This function is called `relative_time`. Having something like this allows you set automations
+to run after a specific amount of time has passed since the last time a sensor or entity was updated.
+
+{{< box tip >}}
+An idea! 💡 For our specific use case, you could set up an automation that sends you a notification if no birds have been detected for
+over 30 minutes. Of course, we'll set parameters like not to notify you at night or during the winter months.
+{{< /box >}}
+
+The issue I faced with relative time has to do with the sensors I created from my AppDaemon script. Relative time expects
+a date _and_ time. I was only passing the time. In Home Assitant if you use the Developer Tools > Template to test relative
+time out on the `sensor.bird_time_seen` sensor, you'll get a result of 126 years... That's because without a date, Home
+Assistant defaults the date to `1900-01-01`. The full relative_time return is `1900-01-01 15:15:15`.
+
+We could go back and set the sensors to include both date and time, but I prefer them separate so that I can use them in
+different places. For this dashboard, the day is always today, so having the date felt redundant. To create a new sensor
+using the `relative_time` function, you'll need to edit your `configuration.yaml`.
+
+Once you're editing your config file, add the following:
+
+```yaml
+template:
+# Bird Time Last Seen
+ - sensor:
+ - name: "Bird Last Seen"
+ state: >
+ {% set birdseen = (states('sensor.bird_date_seen')+' '+states('sensor.bird_time_seen')) %}
+ {% set bird = relative_time(strptime(birdseen, '%Y-%m-%d %H:%M:%S')) %}
+ {{ bird }}
+```
+
+What this does is uses Home Assistant's templating functionality and creates a new sensor called "Bird Last Seen". The
+default `sensor.` name will be `sensor.bird_last_seen`.
+
+To configure the state of that sensor, we first set a variable called `birdseen`. To this variable we are assigning the
+concatenated values of `bird_date_seen`, a single whitespace, and `bird_time_seen`. We're choosing this format because that
+is the format that `relative_time` returned before when we tried using it without a date.
+
+As a quick experiment, take the templating code under the `state: >` parameter above and throw it into Developer Tools >
+Template. Do you get 126 years? Or something more realistic? If something more realistic, amazing!
+
+We're almost there! Here's what you should see in HomeAssistant if the sensor was created correctly.
+
+
+{{< box info >}}
+If you're new to templating for Home Assistant (or in general!) it would be helpful to read through a few of the docs that
+HomeAssistant provides.
+
+* [HomeAssistant Templating Docs](https://www.home-assistant.io/docs/configuration/templating/)
+* [Jinja2 Templating Engine Docs](https://palletsprojects.com/p/jinja)
+
+_Note: Jinja2 is very popular and common. Learning it for home automation is worth it alone, but it may very well come in
+handy in other places too!_
+{{< /box >}}
+
+{{< details "Data Card Yaml" >}}
+
+```yaml
+type: horizontal-stack
+cards:
+ - type: custom:button-card
+ entity: sensor.bird_time_seen
+ show_state: true
+ show_icon: true
+ show_name: false
+ icon: mdi:clock-outline
+ color: darkgrey
+ styles:
+ card:
+ - border: none
+ - background: transparent
+ - type: custom:button-card
+ entity: sensor.bird_confidence
+ show_state: true
+ show_icon: true
+ show_name: false
+ icon: mdi:check-circle
+ styles:
+ card:
+ - border: none
+ - background: transparent
+ icon:
+ - color: |
+ [[[
+ if (states['sensor.bird_confidence'].state > 80 )
+ return "green";
+ return "lightblue";
+ ]]]
+ - type: custom:button-card
+ entity: sensor.bird_last_seen
+ show_state: true
+ show_icon: true
+ show_name: false
+ icon: mdi:timer-refresh-outline
+ styles:
+ card:
+ - border: none
+ - background: transparent
+ icon:
+ - color: |
+ [[[
+ var y = states['sensor.bird_last_seen'].state;
+ let x = y.slice(0, 2);
+ var e = Number(x);
+ if (e < 5) return '#ff6969';
+ if (e < 10) return '#ffdf87';
+ if (e < 15) return '#d9d76f';
+ if (e < 20) return '#fcc2ea';
+ else return '#ccccc8';
+ ]]]
+
+```
+
+{{< /details >}}
+
+## Weather Card
+
+
+
+This doesn't need a lot of explaining or instructions. It is just the standard weather card! Here's the YAML, none of the
+less, so you know what I toggled on/off. I'm using [Pirate Weather Integration](https://pirateweather.net/en/latest/) as my
+data source.
+
+{{< details "Weather Card" >}}
+
+```yaml
+type: custom:weather-card
+entity: weather.pirateweather
+forecast: false
+hourly_forecast: false
+name: null
+details: true
+current: true
+number_of_forecasts: '5'
+```
+
+{{< /details >}}
+
+## Description Card
+
+Finally, we reach the bottom of the dashboard: the description card. This one is also really straightforward. We're just
+using a [standard markdown card](https://www.home-assistant.io/dashboards/markdown/) and taking the description sensor we
+created using Wikipedia's API and making that the main content of the card.
+
+
+
+Other than setting the theme, the only other small changes are removing the border and increasing from the default font size.
+We'll use [Thomas Loven's](https://github.com/thomasloven) famous Card Mod for that.
+
+{{< details "Description Card">}}
+
+```yaml
+type: markdown
+content: '{{ state_attr(''sensor.birdnet_wiki'',''description'')}}'
+theme: Catppuccin Mocha
+card_mod:
+ style: |
+ ha-card.type-markdown {
+ border: none;
+ }
+ ha-markdown {
+ font-size: 16px;
+ }
+```
+
+{{< /details >}}
+
+## Conclusion
+
+And that's all there is to it! I say that flippantly, but I know that it can seem like there's a lot of setup. Everything I
+did here evolved out of other people's projects and dashboards on [Reddit](www.reddit.com/r/homeassistant) or the invaluable
+[HomeAssistant Community](https://community.home-assistant.io/)
+
+Please feel free to reach out to me on [Mastodon](www.fosstodon.org/@notnorm) if you have any questions or get stuck
+anywhere!
+
+## Full Dashboard YAML
+
+{{< details "Full Dashboard YAML" >}}
+
+```yaml
+- theme: Catppuccin Macchiato
+ title: BirdNet-Dashboard
+ path: birdnet-dashboard
+ icon: mdi:bird
+ type: custom:vertical-layout
+ badges: []
+ cards:
+ - type: horizontal-stack
+ cards:
+ - type: custom:button-card
+ entity: sensor.bird_common_name
+ triggers_update: all
+ show_name: false
+ show_icon: false
+ show_state: false
+ show_label: false
+ styles:
+ card:
+ - background: transparent
+ - border: none
+ - width: 215px
+ - height: 175px
+ custom_fields:
+ picture:
+ card:
+ type: custom:button-card
+ entity: camera.birdnet_flickr
+ show_entity_picture: true
+ show_name: false
+ show_icon: false
+ styles:
+ card:
+ - height: 100%
+ - width: 100%
+ - padding: 0px 15px 0px 15px
+ - border-radius: 3px 3px 15px 3px
+ - border: none
+ - background: transparent
+ - overflow: visible
+ img_cell:
+ - width: 180px
+ - height: 160px
+ - border-radius: 69%
+ - border: 3px solid grey
+ entity_picture:
+ - width: 215px
+ - height: 100%
+ - type: vertical-stack
+ cards:
+ - type: custom:button-card
+ entity: sensor.bird_common_name
+ show_entity_picture: true
+ show_state: true
+ show_name: false
+ show_icon: false
+ styles:
+ card:
+ - background: transparent
+ - border: none
+ - margin-top: 35px
+ - font-size: 25px
+ - width: auto
+ - type: custom:button-card
+ entity: sensor.bird_science_name
+ show_entity_picture: true
+ show_state: true
+ show_name: false
+ show_icon: false
+ styles:
+ card:
+ - background: transparent
+ - border: black
+ - width: auto
+ - type: horizontal-stack
+ cards:
+ - type: custom:button-card
+ entity: sensor.bird_time_seen
+ show_state: true
+ show_icon: true
+ show_name: false
+ icon: mdi:clock-outline
+ color: darkgrey
+ styles:
+ card:
+ - border: none
+ - background: transparent
+ - type: custom:button-card
+ entity: sensor.bird_confidence
+ show_state: true
+ show_icon: true
+ show_name: false
+ icon: mdi:check-circle
+ styles:
+ card:
+ - border: none
+ - background: transparent
+ icon:
+ - color: |
+ [[[
+ if (states['sensor.bird_confidence'].state > 80 )
+ return "green";
+ return "lightblue";
+ ]]]
+ - type: custom:button-card
+ entity: sensor.bird_last_seen
+ show_state: true
+ show_icon: true
+ show_name: false
+ icon: mdi:timer-refresh-outline
+ styles:
+ card:
+ - border: none
+ - background: transparent
+ icon:
+ - color: |
+ [[[
+ var y = states['sensor.bird_last_seen'].state;
+ let x = y.slice(0, 2);
+ var e = Number(x);
+ if (e < 5) return '#ff6969';
+ if (e < 10) return '#ffdf87';
+ if (e < 15) return '#d9d76f';
+ if (e < 20) return '#fcc2ea';
+ else return '#ccccc8';
+ ]]]
+ - type: custom:weather-card
+ entity: weather.pirateweather
+ forecast: false
+ hourly_forecast: false
+ name: null
+ details: true
+ current: true
+ - type: markdown
+ content: '{{ state_attr(''sensor.birdnet_wiki'',''description'')}}'
+ theme: Catppuccin Mocha
+ card_mod:
+ style: |
+ ha-card.type-markdown {
+ border: none;
+ }
+ ha-markdown {
+ font-size: 16px;
+ }
+```
+
+{{< /details >}}
+
+
diff --git a/content/posts/hosting_hugo_troubles.md b/content/posts/hosting_hugo_troubles.md
index 2cded39..71d85ef 100644
--- a/content/posts/hosting_hugo_troubles.md
+++ b/content/posts/hosting_hugo_troubles.md
@@ -20,11 +20,11 @@ ShowPostNavLinks: true
ShowWordCount: true
ShowRssButtonInSectionTermList: true
UseHugoToc: true
-#cover:
-# image: "" # image path/url
-# alt: "" # alt text
-# caption: "" # display caption under cover
-# relative: false # when using page bundles set this to true
+cover:
+ image: "hugo-nginx-trouble.png"
+ alt: "Hugo Logo, Nginx Logo, Tired Face emoji"
+ caption: "Hosting Hugo on a self-hosted nginx server brought some troubles!"
+ relative: false # when using page bundles set this to true
# hidden: true # only hide on current single page
---
diff --git a/content/posts/img/.DS_Store b/content/posts/img/.DS_Store
new file mode 100644
index 0000000..5008ddf
Binary files /dev/null and b/content/posts/img/.DS_Store differ
diff --git a/content/posts/img/birdnet-homeassistant-birdseen-sensor.png b/content/posts/img/birdnet-homeassistant-birdseen-sensor.png
new file mode 100644
index 0000000..1ddf62e
Binary files /dev/null and b/content/posts/img/birdnet-homeassistant-birdseen-sensor.png differ
diff --git a/content/posts/img/birdnet-homeassistant-dash-full.png b/content/posts/img/birdnet-homeassistant-dash-full.png
new file mode 100644
index 0000000..c9bb3dd
Binary files /dev/null and b/content/posts/img/birdnet-homeassistant-dash-full.png differ
diff --git a/content/posts/img/birdnet-homeassistant-data-card.png b/content/posts/img/birdnet-homeassistant-data-card.png
new file mode 100644
index 0000000..9ec7010
Binary files /dev/null and b/content/posts/img/birdnet-homeassistant-data-card.png differ
diff --git a/content/posts/img/birdnet-homeassistant-description-card.png b/content/posts/img/birdnet-homeassistant-description-card.png
new file mode 100644
index 0000000..d605167
Binary files /dev/null and b/content/posts/img/birdnet-homeassistant-description-card.png differ
diff --git a/content/posts/img/birdnet-homeassistant-overview-card.png b/content/posts/img/birdnet-homeassistant-overview-card.png
new file mode 100644
index 0000000..f5294fc
Binary files /dev/null and b/content/posts/img/birdnet-homeassistant-overview-card.png differ
diff --git a/content/posts/img/birdnet-homeassistant-weather-card.png b/content/posts/img/birdnet-homeassistant-weather-card.png
new file mode 100644
index 0000000..d8fb65f
Binary files /dev/null and b/content/posts/img/birdnet-homeassistant-weather-card.png differ
diff --git a/content/posts/zyxel_vlan_setup.md b/content/posts/zyxel_vlan_setup.md
new file mode 100644
index 0000000..4747b15
--- /dev/null
+++ b/content/posts/zyxel_vlan_setup.md
@@ -0,0 +1,28 @@
+---
+title: 'Zyxel_vlan_setup'
+date: 2023-10-04T10:35:41-04:00
+tags: [""]
+author: "Me"
+showToc: true
+TocOpen: false
+draft: true
+hidemeta: false
+description: 'zyxel_vlan_setup'
+disableHLJS: true
+disableShare: false
+disableHLJS: false
+hideSummary: false
+searchHidden: true
+ShowReadingTime: true
+ShowBreadCrumbs: true
+ShowPostNavLinks: true
+ShowWordCount: true
+ShowRssButtonInSectionTermList: true
+UseHugoToc: true
+cover:
+ image: ""
+ alt: ""
+ caption: ""
+ relative: false
+ hidden: true
+---
diff --git a/hugo.yaml b/hugo.yaml
index 2101ae4..485eed0 100644
--- a/hugo.yaml
+++ b/hugo.yaml
@@ -9,6 +9,13 @@ themesDir: './themes/'
paginate: 7
googleAnalytics: G-X8VR5M0K20
+enableRobotsTXT: true
+sectionPagesMenu: main
+
+taxonomies:
+ category: categories
+ series: series
+ tag: tags
# Allow html to be rendered in Markdown files
markup:
@@ -30,6 +37,8 @@ params:
author: Norm Rasmussen
DateFormat: "January 2, 2006"
defaultTheme: dark
+ ShowShareButtons: true
+ ShowBreadCrumbs: true
assets:
favicon: "favicon.ico"
favicon32x32: "rsmsncircles.ico"
diff --git a/layouts/details.html b/layouts/details.html
new file mode 100644
index 0000000..62e1dcb
--- /dev/null
+++ b/layouts/details.html
@@ -0,0 +1,4 @@
+
+ {{ (.Get 0) | markdownify }}
+ {{ .Inner | markdownify }}
+
diff --git a/public/404.html b/public/404.html
index f9ad696..f5f69d9 100644
--- a/public/404.html
+++ b/public/404.html
@@ -84,6 +84,11 @@ if (!doNotTrack) {
Checking for Entities If you’re following up on this from my first post, you’ve already added your AppDaemon script and confirmed that the AppDaemon logs don’t show any errors. Now is the true test if it’s working: do you have the new sensors in HomeAssistant?!
+The best way to do this is by just type e from any screen in the HomeAssistant UI! That will bring up a list of entities....
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/categories/tutorial/index.xml b/public/categories/tutorial/index.xml
new file mode 100644
index 0000000..2d160cb
--- /dev/null
+++ b/public/categories/tutorial/index.xml
@@ -0,0 +1,20 @@
+
+
+
+ Tutorial on Norm-working Packets 💾
+ /categories/tutorial.html
+ Recent content in Tutorial on Norm-working Packets 💾
+ Hugo -- gohugo.io
+ en-us
+ Wed, 04 Oct 2023 10:35:23 -0400
+
+ BirdNET-PI & HomeAssistant: Part 2
+ /posts/birdnet_homeassistant_part2.html
+ Wed, 04 Oct 2023 10:35:23 -0400
+
+ /posts/birdnet_homeassistant_part2.html
+ A Follow up from the previous post, this tutorial takes all the sensors we created and loads them into a beautiful dashboard!
+
+
+
+
diff --git a/public/categories/tutorial/page/1.html b/public/categories/tutorial/page/1.html
new file mode 100644
index 0000000..ed0acbf
--- /dev/null
+++ b/public/categories/tutorial/page/1.html
@@ -0,0 +1,10 @@
+
+
+
+ /categories/tutorial.html
+
+
+
+
+
+
diff --git a/public/hugo-nginx-trouble.png b/public/hugo-nginx-trouble.png
new file mode 100644
index 0000000..ea02b1d
Binary files /dev/null and b/public/hugo-nginx-trouble.png differ
diff --git a/public/index.html b/public/index.html
index bd628ea..683e220 100644
--- a/public/index.html
+++ b/public/index.html
@@ -99,6 +99,11 @@ if (!doNotTrack) {
Checking for Entities If you’re following up on this from my first post, you’ve already added your AppDaemon script and confirmed that the AppDaemon logs don’t show any errors. Now is the true test if it’s working: do you have the new sensors in HomeAssistant?!
+The best way to do this is by just type e from any screen in the HomeAssistant UI! That will bring up a list of entities....
+
+
+
+
+
+
+
+
+
+
Creating a BirdNetPi Dashboard in HomeAssistant - Part 1
+
+
+
+
This is Part One of a Two Part Series. You can find Part Two, here.
+What you will need BirdNET-Pi HomeAssistant AppDaemon MQTT Broker (I use Mosquitto) Background In early 2023, at the height of the Raspberry Pi shortage I felt like a king with an extra Rpi laying around, not being used. I’m a big fan of any sort of passive intake of information and had been looking around for various citizen science-style projects that can capture information from the world around me....
+
+
+
+
+
@@ -152,6 +187,8 @@ I really enjoy self-hosting services that I use everyday. One of those includes
+
+
Trouble Hosting Hugo with Nginx
diff --git a/public/index.xml b/public/index.xml
index 6276450..e4fe1ac 100644
--- a/public/index.xml
+++ b/public/index.xml
@@ -6,7 +6,25 @@
Recent content on Norm-working Packets 💾Hugo -- gohugo.ioen-us
- Fri, 22 Sep 2023 15:07:10 -0400
+ Wed, 04 Oct 2023 10:35:23 -0400
+
+ BirdNET-PI & HomeAssistant: Part 2
+ /posts/birdnet_homeassistant_part2.html
+ Wed, 04 Oct 2023 10:35:23 -0400
+
+ /posts/birdnet_homeassistant_part2.html
+ A Follow up from the previous post, this tutorial takes all the sensors we created and loads them into a beautiful dashboard!
+
+
+
+ Creating a BirdNetPi Dashboard in HomeAssistant - Part 1
+ /posts/birdnet_homeassistant.html
+ Sat, 30 Sep 2023 11:21:55 -0400
+
+ /posts/birdnet_homeassistant.html
+ Learn how to take BirdNET-Pi Detections to create and display entities in HomeAssistant.
+
+
Pushing a Single Local Git Repo to Multiple Remote Repos
/posts/multiple_git_remotes.html
diff --git a/public/posts.html b/public/posts.html
index 57ec9f2..efad79d 100644
--- a/public/posts.html
+++ b/public/posts.html
@@ -100,16 +100,51 @@ if (!doNotTrack) {
Checking for Entities If you’re following up on this from my first post, you’ve already added your AppDaemon script and confirmed that the AppDaemon logs don’t show any errors. Now is the true test if it’s working: do you have the new sensors in HomeAssistant?!
+The best way to do this is by just type e from any screen in the HomeAssistant UI! That will bring up a list of entities....
+
+
+
+
+
+
+
+
+
+
Creating a BirdNetPi Dashboard in HomeAssistant - Part 1
+
+
+
+
This is Part One of a Two Part Series. You can find Part Two, here.
+What you will need BirdNET-Pi HomeAssistant AppDaemon MQTT Broker (I use Mosquitto) Background In early 2023, at the height of the Raspberry Pi shortage I felt like a king with an extra Rpi laying around, not being used. I’m a big fan of any sort of passive intake of information and had been looking around for various citizen science-style projects that can capture information from the world around me....
+
+
+
+
+
@@ -126,6 +161,8 @@ I really enjoy self-hosting services that I use everyday. One of those includes
+
+
Trouble Hosting Hugo with Nginx
diff --git a/public/posts/birdnet_homeassistant.html b/public/posts/birdnet_homeassistant.html
index ba2accf..026c438 100644
--- a/public/posts/birdnet_homeassistant.html
+++ b/public/posts/birdnet_homeassistant.html
@@ -44,8 +44,8 @@ if (!doNotTrack) {
-
-
+
+
@@ -80,8 +80,8 @@ if (!doNotTrack) {
"articleBody": "This is Part One of a Two Part Series. You can find Part Two, here.\nWhat you will need BirdNET-Pi HomeAssistant AppDaemon MQTT Broker (I use Mosquitto) Background In early 2023, at the height of the Raspberry Pi shortage I felt like a king with an extra Rpi laying around, not being used. I’m a big fan of any sort of passive intake of information and had been looking around for various citizen science-style projects that can capture information from the world around me. Since I’m already running an ADS-B antenna with Flight Aware, I figured this next project would deal with radio waves/transmissions. Instead, to my amazement, I discovered BirdNET-Pi!\nWhat is BirdNET-Pi? In case you didn’t click the links above, BirdNET-Pi is an app built specifically made for Rapsberry Pi devices, that builds off the BirdNET Framework. BirdNET is one of the most advanced acoustic monitoring tools available for passively monitoring bird diversity populations. Where BirdNET-Pi takes it to the next level is the ability to setup an SBC - hopefully enclosed in a waterproof space! - and monitor birds in your local environment over time.\nI think this project is beyond neat. It runs a bit slow on a Raspberry Pi 3, but overall it runs smoothly. I was even able to contribute a PR to the project in April when I noticed a bug in the platform after a hard reset of my Pi.\nBirdNET-PI Notification Setup - MQTT Once you have BirdNET-Pi up and running, you’ll need to head over to the Settings and setup the correct MQTT payloads. Here are the possible variables you can pass in an MQTT payload:\n$sciname: Scientific Name $comname: Common Name $confidence: Confidence Score $confidencepct: Confidence Score as a percentage (eg. 0.91 =\u003e 91) $listenurl: A link to the detection $date: Date $time: Time $week: Week $latitude: Latitude $longitude: Longitude $cutoff: Minimum Confidence set in “Advanced Settings” $sens: Sigmoid Sensitivity set in “Advanced Settings” $overlap: Overlap set in “Advanced Settings” $flickrimage: A preview image of the detected species from Flickr. Set your API key below. For our purposes, we will only be using $comname, $sciname, $date, $time, $week, and $confidence. However, this entire process is extremely customizable, which you’ll learn more about in the AppDaemon section. Please expand on it and include information that is pertinent to your own uses.\nHere is how I’ve setup my MQTT payload from BirdNET-Pi Settings:\nHere it is in text form:\nNotification Title: $comname, Notification Body: $sciname, $date, $time, $week, $confidence [ ] Notify each new infrequent species detection (\u003c 5 visits per week) [ ] Notify each new species first detection of the day [X] Notify each new detection [X] Send weekly report Minimum time between notifications of the same species (sec): 5 To test my MQTT notifications, I use the iOS client “MQTTool”. After signing up, head to “Subscribe” and type birdnet as the topic and then click Subscribe. If everything is setup correctly and there are birds being recorded by the BirdNET-Pi’s microphone, you should start seeing those detections in the MQTTool app. If so, fantastic news! Let’s move onto AppDaemon.\nAppDaemon Script Now that we have the Pi communicating via MQTT, it’s time to get that information into HomeAssistant. I’ve shared the full script at the bottom of this page, but let’s jump into each section. This is not a full tutorial of how to use AppDaemon, but it may help fill in any knowledge gaps with the system.\nImports First, we’re going to import time and requests. We’re going to use time as a backup to the $time component in the payload. This can be helpful to see if there delays, or if BirdNET-Pi stopped detecting. We’re then going to use requests to pull from Wikipedia’s API and grab a description for our HomeAssistant Dashboard.\nClass Definition To start any AppDaemon app, you need to include a Class that is defined in the apps.yaml file. This is also where we initialize and define the various items that will be used in the remainder of the script.\nclass birdnet(adbase.ADBase): def initialize(self): self.hassapi = self.get_plugin_api(\"HASS\") self.adapi = self.get_ad_api() self.mqttapi = self.get_plugin_api(\"MQTT\") self.birdnet_mqtt = \"birdnet\" self.mqttapi.listen_event( self.birdnet_message, \"MQTT_MESSAGE\", topic=self.birdnet_mqtt ) For this script, we need to use a lot of the AppDaemon APIs across more than just HomeAssistant, so we’re going to be using ADBase. By using that, we can initialize the various APIs, which we do in the next 3 lines. In these 3 lines we need to get access to HomeAssistant’s APIs, AppDaemon’s APIs, and MQTT APIs - the first and third items are plugins of AppDaemon, and AppDaemon is… well… AppDaemon! Here are a few reference docs:\nMQTT AppDaemon API HomeAssistant AppDaemon API AppDaemon API These will indispensable to you as you leverage AppDaemon and expand this little script.\nOnce we have access to that, we need to setup the main topic for MQTT from BirdNET-Pi and finally, what event we are listening for that will trigger the functions in the rest of the script. self.birdnet_mqtt = \"birdnet\" is the definition for the MQTT topic. Let’s breakdown the last line of the class.\nHere’s a breakdown of each of the items in that last line. You can find the official documentation here.\nself.mqttapi.listen_event - this is what we use in AppDaemon to listen for an MQTT event in order to trigger a function. self.birdnet_message - the name of the function you’d like to trigger \"MQTT_MESSAGE\" - The default event in AppDaemon’s MQTT API plugin. This is used because MQTT doesn’t keep a state in this plugin. topic=self.birdnet_mqtt - The topic that will be received to trigger the function. Defined on the previous line. In other words, what we are telling AppDaemon is the following: “When AppDaemon’s MQTT API plugin receives a message with the topic of ‘birdnet’, run the function birdnet_message.”\nbirdnet_message Function Part 1: Variables Management Now we get into our first function of the script. The first portion of this script is splitting up the payload that we defined from the BirdNET-Pi UI into individual variables that we can better manage later on. If you test this script out by adding print() statements at various points, you’ll notice that the payload is received with the following json formatting:\n{ \"payload\": { \"data\": \"data\" } } As such, we need to look inside the payload to begin grabbing the data. The pre_split variable is now just looking at the data inside the payload and the rest of the variables take all the date into the payload, split it by the comma, and then grab the string by their index. If you remember what we did above above, you’ll see that we have the various BirdNET information at each of the indexes in the AppDaemon script - 0 through 5.\nPart 2: Re-Publishing MQTT Payloads This next section is shooting all the variables we just defined back via MQTT. The reason why we do it this way is because we need HomeAssistant to grab each of these variables as individual sensors. BirdNET doesn’t give us that capability - it’s a single message with all the information in one. [Here is the documentation from AppDaemon](## BirdNET-PI Notification Setup - MQTT ) on mqtt_publish. Later on, I’ll show you how to ensure that HomeAssistant takes those topic payloads and adds them as entities in your HA setup.\nPart 3: Wikipedia Sensor The next eight lines are a fairly straightforward API call to Wikipedia. We start out by passing the science_name into the URL. The rest of the flags that we are passing into the URL comes from Wikipedia’s Docs. url = f\"https://en.wikipedia.org/w/api.php?format=json\u0026action=query\u0026prop=extracts\u0026exintro\u0026explaintext\u0026redirects=1\u0026titles={science_name}\"\nOnce that’s done we call it with response.get(url) and format it with response.json(). Wikipedia returns the json payload with the top level of query (which was our action in the url ;) ), and we’re looking for the value within that query.\nAll that’s left is to take that query value and push it to HomeAssistant! We can do that with the self.hassapi.set_state function. Within the parenthesis we define the name of the sensor (sensor.birdnet_wiki), what it’s state should be (on), and any attributes associated with the entity. Since we can’t assign a long description to the basic status of the entity, we’re adding an attribute with the key of description and the value will be the wikipedia description garnered from the API call.\nurl = f\"https://en.wikipedia.org/w/api.php?format=json\u0026action=query\u0026prop=extracts\u0026exintro\u0026explaintext\u0026redirects=1\u0026titles={science_name}\" response = requests.get(url) response = response.json() for value in response['query']['pages']: wiki_desc = response['query']['pages'][value]['extract'] self.hassapi.set_state(\"sensor.birdnet_wiki\", state='on', attributes = {\"description\": wiki_desc}) Part 4: Generate Picture for Detection (Optional) This part is optional but I noticed that BirdNET-Pi was already grabbing a Flickr Picture for it’s front end, so I took the code from the BirdNET code base and adjusted it a bit for my needs. This will work very similarly to the Wikipedia API call, the main difference here being that you need an API key for Flickr. You can find more information here.\nGiven Flickr’s fairly robust API, by passing in the detected bird’s common name, we get amazing results from the community of various pictures of the same species of bird. Ever since I’ve set this up, I’ve not seen a mislabeled picture in my dashboard!\nThe most confusion portion of this section is the image_url as you’ll notice a bunch of data[\"value\"] strings at various portions of the URL. The short answer to this is in the previous line with the data variable. A successful query has Flickr returning a large payload of information. We’re specifically using this Flickr API endpoint. While you can pass a lot of variables for your needs, if you scroll down, you can see that the example response contains multiple photos in a single response. We’re passing per_page=5 to limit some of those response items. Left out of that response, though, is a one-stop-shop for a URL to that photo. Thankfully, Flickr can help us put together a URL from the data in the response.\nNote: Full Transparency that I only learned about this after reading through BirdNET-Pi’s code base. Full credit goes to mcguirepr89. For additional reference, here is Flickr’s official page on construction photo image URLS\nWith this response, we now have the variables we need to construct the URL to actually render the image. Those variables are: Farm ID, Server ID, ID and Secret. I haven’t yet looked into why we need “farm” when the official documentation doesn’t state anything about it.\nAlmost there! We now do the same as we did with the Wikipedia API response. We create a sensor in HomeAssistant! We’re calling this sensor sensor.birdpic, ensuring the state=on, and giving it the attributes of the image_url as garnered from Flickr.\nheaders = {'User-Agent': 'Python_Flickr/1.0'} flickr_api = \"enter_your_api_key\" flickr_url = f\"https://www.flickr.com/services/rest/?method=flickr.photos.search\u0026api_key={flickr_api}\u0026text={common_name} bird\u0026sort=relevance\u0026per_page=5\u0026media=photos\u0026format=json\u0026nojsoncallback=1\" flickr_resp = requests.get(url=flickr_url, headers=headers) data = flickr_resp.json()[\"photos\"][\"photo\"][0] image_url = 'https://farm'+str(data[\"farm\"])+'.static.flickr.com/'+str(data[\"server\"])+'/'+str(data[\"id\"])+'_'+str(data[\"secret\"])+'_n.jpg' self.hassapi.set_state(\"sensor.birdpic\", state='on', attributes={\"image\": image_url}) In Part 2 of this article, we’ll take a look at Home Assistant, see what these sensors look like, and create a rudimentary dashboard.\nBirdnet AppDaemon Script import time import requests class birdnet(adbase.ADBase): def initialize(self): self.hassapi = self.get_plugin_api(\"HASS\") self.adapi = self.get_ad_api() self.mqttapi = self.get_plugin_api(\"MQTT\") self.birdnet_mqtt = \"birdnet\" self.mqttapi.listen_event( self.birdnet_message, \"MQTT_MESSAGE\", topic=self.birdnet_mqtt ) def birdnet_message(self, event_name, data, kwargs): pre_split = data[\"payload\"] common_name = pre_split.split(',')[0].strip() science_name = pre_split.split(',')[1].strip() date_seen = pre_split.split(',')[2].strip() time_seen = pre_split.split(',')[3].strip() week_seen = pre_split.split(',')[4].strip() confidence = pre_split.split(',')[5].strip() # print(f\"A {common_name} was seen on {date_seen} at {time_seen}. Confidence is {confidence}.\") self.mqttapi.mqtt_publish(\"birdnet/sensors/common_name\", common_name) self.mqttapi.mqtt_publish(\"birdnet/sensors/science_name\", science_name) self.mqttapi.mqtt_publish(\"birdnet/sensors/time_seen\", time_seen) self.mqttapi.mqtt_publish(\"birdnet/sensors/date_seen\", date_seen) self.mqttapi.mqtt_publish(\"birdnet/sensors/confidence\", confidence) url = f\"https://en.wikipedia.org/w/api.php?format=json\u0026action=query\u0026prop=extracts\u0026exintro\u0026explaintext\u0026redirects=1\u0026titles={science_name}\" response = requests.get(url) response = response.json() for value in response['query']['pages']: wiki_desc = response['query']['pages'][value]['extract'] self.hassapi.set_state(\"sensor.birdnet_wiki\", state='on', attributes = {\"description\": wiki_desc}) headers = {'User-Agent': 'Python_Flickr/1.0'} flickr_api = \"enter_your_api_key\" flickr_url = f\"https://www.flickr.com/services/rest/?method=flickr.photos.search\u0026api_key={flickr_api}\u0026text={common_name} bird\u0026sort=relevance\u0026per_page=5\u0026media=photos\u0026format=json\u0026nojsoncallback=1\" flickr_resp = requests.get(url=flickr_url, headers=headers) data = flickr_resp.json()[\"photos\"][\"photo\"][0] image_url = 'https://farm'+str(data[\"farm\"])+'.static.flickr.com/'+str(data[\"server\"])+'/'+str(data[\"id\"])+'_'+str(data[\"secret\"])+'_n.jpg' self.hassapi.set_state(\"sensor.birdpic\", state='on', attributes={\"image\": image_url}) ",
"wordCount" : "1953",
"inLanguage": "en",
- "image":"/birdnet-homeassistant.png","datePublished": "2023-09-25T12:51:55-04:00",
- "dateModified": "2023-09-25T12:51:55-04:00",
+ "image":"/birdnet-homeassistant.png","datePublished": "2023-09-30T11:21:55-04:00",
+ "dateModified": "2023-09-30T11:21:55-04:00",
"author":{
"@type": "Person",
"name": "Me"
@@ -138,6 +138,11 @@ if (!doNotTrack) {
If you’re following up on this from my first post, you’ve already added your AppDaemon script and confirmed that the AppDaemon logs don’t show any errors. Now is the true test if it’s working: do you have the
+new sensors in HomeAssistant?!
+
+
+
+
+
+
+
+
+
+
The best way to do this is by just type e from any screen in the HomeAssistant UI! That will bring up a list of entities.
+Start typing “bird” or “birdnet” and you should see the new entities listed there.
Now that we have the correct entities, lets take a look at what we’re working with. Full disclosure that once I got this
+working, I haven’t really revisited it, refactored it, or made any improvements. I’m sure you’ll find ways to use less YAML,
+but I wanted to get this out there sooner than later!
+
+
+
I’ve include the code for all the cards at the bottom of this post. You can find them [here]/posts/birdnet_homeassistant_part2.html#dashboard-yaml. This dashboard is pretty simple, it brings in almost all of the sensors
+we created in the first post and organizes them in an as-pleasant-as-possible view. I’m definitely not a designer, so some of
+the colors could be worked on…
You’ll notice from the few dependencies listed above, that I use this button card. A lot.
+RomRider did a fantastic job of adding in a ton of flexibility into the card. For the overview
+card, we’re taking one of the entities, in this case, bird_common_name and attaching the Flickr picture/sensor to it. Then,
+on the right, I’m displaying the name and common name. Here’s the overview card’s yaml.
+
The tricky or tedious part of this card is making sure most of the card’s attributes (icon, name, state, label) are set to
+false. Another option for the Common and Scientific name on the right is to use a markdown card. I couldn’t get the
+formatting just right when using that card and some grid-card tricks, so I opted to reuse the super flexible button-card.
+
Pay attention to the styles for the image (lines 24-40). Those are what keep the border around the image along with the image
+a certain height and width so that it looks proportional on the page.
+
One additional thing I have been toying with but hadn’t finalized was messing with [img_cell][border]. By adding some
+javascript in that section (see other cards), you could change the color of the border based on another parameter. Perhaps
+you look at the state of sensor.bird_common_name and if there is the name of a color in there, that’s the border’s color.
+Feel free to get crazy and creative with this!
This card is fairly straight forward in that it’s showing 3 key data points: the time of detection, detection confidence,
+how long ago it was seen. This could be fairly redundant since we already have the time of detection, but when you’re just
+quickly glancing at the dashboard, minutes ago is much faster brain processing than comparing the timestamp and the current
+time.
+
You’ve likely picked up by now that in the previous post, we never sent a payload to create the sensor.bird_last_seen
+entity. Here’s how you can do it.
When I first set out to create this sensor, I was messing with jinja templates for timestamp, datetime, strptime, and more.
+Here are a few code blocks I saved in my notes in case I went too far down the wrong path. Here are a few of them.
The thing is, HomeAssistant has already implemented this really neat feature for calculating time, especially from when
+something was last updated. This function is called relative_time. Having something like this allows you set automations
+to run after a specific amount of time has passed since the last time a sensor or entity was updated.
+
+
+
+
+
+
+
An idea! 💡 For our specific use case, you could set up an automation that sends you a notification if no birds have been detected for
+over 30 minutes. Of course, we’ll set parameters like not to notify you at night or during the winter months.
+
+
+
The issue I faced with relative time has to do with the sensors I created from my AppDaemon script. Relative time expects
+a date and time. I was only passing the time. In Home Assitant if you use the Developer Tools > Template to test relative
+time out on the sensor.bird_time_seen sensor, you’ll get a result of 126 years… That’s because without a date, Home
+Assistant defaults the date to 1900-01-01. The full relative_time return is 1900-01-01 15:15:15.
+
We could go back and set the sensors to include both date and time, but I prefer them separate so that I can use them in
+different places. For this dashboard, the day is always today, so having the date felt redundant. To create a new sensor
+using the relative_time function, you’ll need to edit your configuration.yaml.
+
Once you’re editing your config file, add the following:
+
template:
+# Bird Time Last Seen
+ - sensor:
+ - name: "Bird Last Seen"
+state: >
+ {% set birdseen = (states('sensor.bird_date_seen')+' '+states('sensor.bird_time_seen')) %}
+ {% set bird = relative_time(strptime(birdseen, '%Y-%m-%d %H:%M:%S')) %}
+ {{ bird }}
+
What this does is uses Home Assistant’s templating functionality and creates a new sensor called “Bird Last Seen”. The
+default sensor. name will be sensor.bird_last_seen.
+
To configure the state of that sensor, we first set a variable called birdseen. To this variable we are assigning the
+concatenated values of bird_date_seen, a single whitespace, and bird_time_seen. We’re choosing this format because that
+is the format that relative_time returned before when we tried using it without a date.
+
As a quick experiment, take the templating code under the state: > parameter above and throw it into Developer Tools >
+Template. Do you get 126 years? Or something more realistic? If something more realistic, amazing!
+
We’re almost there! Here’s what you should see in HomeAssistant if the sensor was created correctly.
+
+
+
+
+
+
+
+
+
If you’re new to templating for Home Assistant (or in general!) it would be helpful to read through a few of the docs that
+HomeAssistant provides.
This doesn’t need a lot of explaining or instructions. It is just the standard weather card! Here’s the YAML, none of the
+less, so you know what I toggled on/off. I’m using Pirate Weather Integration as my
+data source.
Finally, we reach the bottom of the dashboard: the description card. This one is also really straightforward. We’re just
+using a standard markdown card and taking the description sensor we
+created using Wikipedia’s API and making that the main content of the card.
+
+
+
Other than setting the theme, the only other small changes are removing the border and increasing from the default font size.
+We’ll use Thomas Loven’s famous Card Mod for that.
And that’s all there is to it! I say that flippantly, but I know that it can seem like there’s a lot of setup. Everything I
+did here evolved out of other people’s projects and dashboards on Reddit or the invaluable
+HomeAssistant Community
+
Please feel free to reach out to me on Mastodon if you have any questions or get stuck
+anywhere!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/posts/hosting_hugo_troubles.html b/public/posts/hosting_hugo_troubles.html
index a4300f5..635e69a 100644
--- a/public/posts/hosting_hugo_troubles.html
+++ b/public/posts/hosting_hugo_troubles.html
@@ -42,11 +42,13 @@ if (!doNotTrack) {
-
+
+
-
+
+
@@ -78,7 +80,7 @@ if (!doNotTrack) {
"articleBody": "Intro For the last 3 days, I have been spending a few hours after working trying to figure out why my brand new Hugo site was not loading correctly on my sub-domain. For context, I use Nginx to host all my apps and servers, most of them using reverse proxy protocols such as $proxy_host, $forward_scheme, and $port. There are a few more and I’m happy to share some reverse proxy nginx config files. See my post on moving from NPM to Nginx for more information.\nOnce I got the basic idea of this blog up and running, I ran hugo and then used scp to send the files to my nginx host’s public folder. Despite index.html and all the CSS files being in the right spots, I kept getting a few repetitive errors from nginx - either in my browser’s console or in nginx’s log files. I swore I read through every StackOverflow or personal blog post I could find. In fact, the next day, I would sit back down after work to debug and I would continue to find the same sites and posts I found the day before! It was getting frustrating.\nWouldn’t you know… it was one of the simplest solutions that got it all working. Here’s a breakdown of what I was seeing and my hypothesis.\nErrors Console Errors:\nIncorrect MIME type –\u003e css files being set as text/html type. 500/502 Errors when trying to load javascript files 500 Errors when trying to load child pages. Nginx Log Errors for this server:\n[error] 1147432#1147432: *84013 invalid URL prefix in \"://:/favicon-16x16.png\" [warn] 1147432#1147432: *84013 using uninitialized \"port\" variable Nginx error.log errors:\n[error] 1118832#1118832: *77105 directory index of \"/var/www/html/\" is forbidden I thought I had tried everything, but it was a rip and replace from a single blog post that solved it for me. Some of the things I tried include the following. _Note: when I mention ’nginx config file’ below, I am referring to the specific file for this subdomain. I have a single global nginx.conf and then individual files for each subdomain/proxy host.\nEditing index.html to ensure that any referenced file had an explicit mime type associated with it. Included include { full path }/mime.types in the specific nginx config file. Included specific location ~ \\.(css|js)$ { sections in my nginx config file. Tried assigning the $forward_scheme, $host, and $port variables (similar to a reverse proxy host). Removing any SSL references \u003c– This caused similar behavior but different errors! I thought I was making progress…🫥 Switched out the variables of root and alias between my server and location blocks. Started with something super simple, such as the suggestions from Gideon Wolfe’s Block. If you clicked on the link I just shared, you’ll see that Gideon’s setup is quite similar to the one that I finally got to work. My thought there is that my errors were less about the nginx config setup from within the file, and instead it’s very possible that I set incorrect directory permissions after transferring all the public files to the web server. Gideon’s blog was the very first I clicked on, so I owe them my thanks since their site was the entry point to figuring all this out! You can find a list of all the blogs I stumbled upon in this weird and fluctuating journey of doing something as simple as sharing my static files on an nginx web server.\nSolution In the end, newbs.rocks blog post on setting up Hugo with nginx provided me a config example that worked for my setup. I think part of what happened was that as I was cycling through all the blog posts and StackOverflow posts, I would remove one or two lines (usually the one or two I changed from the previous post’s recommendations) but in doing that, was making more of a mess for myself, burying the error even more deeply. By replacing everything, I’ve brought it back to a manageable place.\nYou’ll also notice in my final config file, I was able to add back in the Authelia snippets, paths for the SSL certs, and a few other items that connect nginx to the rest of my infrastructure.\nIf you’ve stumbled upon this, I hope it helps you figure out your Hugo/Nginx issues! I definitely saw a lot of people posting in Hugo’s Discourse asking about mime type errors, so it is very likely that whatever you’re facing isn’t isolated to just you.\nNow that I have this up and running, I need to write (and post!) a script that will pull from my repo, change directory ownership, and reload nginx.\nResources Working Nginx Config File # ------------------------------------------------------------ # selfhosted.rsmsn.co # ------------------------------------------------------------ server { listen 80; listen [::]:80; listen 443 ssl http2; listen [::]:443 ssl http2; server_name selfhosted.rsmsn.co; root /var/www/html/public/; index /index.html; # Force SSL include conf.d/include/force-ssl.conf; # Custom SSL ssl_certificate custom_ssl/npm-3/fullchain.pem; ssl_certificate_key custom_ssl/npm-3/privkey.pem; access_log /var/log/nginx/blog.log combined; error_log /var/log/nginx/blog_error.log warn; include snippets/authelia-location.conf; location / { try_files $uri $uri/ =404; include snippets/authelia-authrequest.conf; } } Blogs and Sites Gideon Wolfe - Deploying a static Hugo site with NGINX Pvera - Deploying a simple static website using Nginx and Hugo Hugo Support thread on Discourse BravosLab - Static website with Hugo and Nginx Cavelab - Hugo Build deploy to Nginx River - Serving Hugo from a non-root location with Nginx ",
"wordCount" : "888",
"inLanguage": "en",
- "datePublished": "2023-09-20T11:33:22-04:00",
+ "image":"/hugo-nginx-trouble.png","datePublished": "2023-09-20T11:33:22-04:00",
"dateModified": "2023-09-20T11:33:22-04:00",
"author":{
"@type": "Person",
@@ -136,6 +138,11 @@ if (!doNotTrack) {
+
diff --git a/public/posts/img/birdnet-homeassistant-birdseen-sensor.png b/public/posts/img/birdnet-homeassistant-birdseen-sensor.png
new file mode 100644
index 0000000..1ddf62e
Binary files /dev/null and b/public/posts/img/birdnet-homeassistant-birdseen-sensor.png differ
diff --git a/public/posts/img/birdnet-homeassistant-dash-full.png b/public/posts/img/birdnet-homeassistant-dash-full.png
new file mode 100644
index 0000000..c9bb3dd
Binary files /dev/null and b/public/posts/img/birdnet-homeassistant-dash-full.png differ
diff --git a/public/posts/img/birdnet-homeassistant-data-card.png b/public/posts/img/birdnet-homeassistant-data-card.png
new file mode 100644
index 0000000..9ec7010
Binary files /dev/null and b/public/posts/img/birdnet-homeassistant-data-card.png differ
diff --git a/public/posts/img/birdnet-homeassistant-description-card.png b/public/posts/img/birdnet-homeassistant-description-card.png
new file mode 100644
index 0000000..d605167
Binary files /dev/null and b/public/posts/img/birdnet-homeassistant-description-card.png differ
diff --git a/public/posts/img/birdnet-homeassistant-overview-card.png b/public/posts/img/birdnet-homeassistant-overview-card.png
new file mode 100644
index 0000000..f5294fc
Binary files /dev/null and b/public/posts/img/birdnet-homeassistant-overview-card.png differ
diff --git a/public/posts/img/birdnet-homeassistant-weather-card.png b/public/posts/img/birdnet-homeassistant-weather-card.png
new file mode 100644
index 0000000..d8fb65f
Binary files /dev/null and b/public/posts/img/birdnet-homeassistant-weather-card.png differ
diff --git a/public/posts/index.xml b/public/posts/index.xml
index 3be6966..92fcd39 100644
--- a/public/posts/index.xml
+++ b/public/posts/index.xml
@@ -6,7 +6,25 @@
Recent content in Posts on Norm-working Packets 💾Hugo -- gohugo.ioen-us
- Fri, 22 Sep 2023 15:07:10 -0400
+ Wed, 04 Oct 2023 10:35:23 -0400
+
+ BirdNET-PI & HomeAssistant: Part 2
+ /posts/birdnet_homeassistant_part2.html
+ Wed, 04 Oct 2023 10:35:23 -0400
+
+ /posts/birdnet_homeassistant_part2.html
+ A Follow up from the previous post, this tutorial takes all the sensors we created and loads them into a beautiful dashboard!
+
+
+
+ Creating a BirdNetPi Dashboard in HomeAssistant - Part 1
+ /posts/birdnet_homeassistant.html
+ Sat, 30 Sep 2023 11:21:55 -0400
+
+ /posts/birdnet_homeassistant.html
+ Learn how to take BirdNET-Pi Detections to create and display entities in HomeAssistant.
+
+
Pushing a Single Local Git Repo to Multiple Remote Repos
/posts/multiple_git_remotes.html
diff --git a/public/posts/multiple_git_remotes.html b/public/posts/multiple_git_remotes.html
index 4bd49b7..2511682 100644
--- a/public/posts/multiple_git_remotes.html
+++ b/public/posts/multiple_git_remotes.html
@@ -138,6 +138,11 @@ if (!doNotTrack) {
Checking for Entities If you’re following up on this from my first post, you’ve already added your AppDaemon script and confirmed that the AppDaemon logs don’t show any errors. Now is the true test if it’s working: do you have the new sensors in HomeAssistant?!
+The best way to do this is by just type e from any screen in the HomeAssistant UI! That will bring up a list of entities....
+
+
+
+
+
+
+
+
+
+
Creating a BirdNetPi Dashboard in HomeAssistant - Part 1
+
+
+
+
This is Part One of a Two Part Series. You can find Part Two, here.
+What you will need BirdNET-Pi HomeAssistant AppDaemon MQTT Broker (I use Mosquitto) Background In early 2023, at the height of the Raspberry Pi shortage I felt like a king with an extra Rpi laying around, not being used. I’m a big fan of any sort of passive intake of information and had been looking around for various citizen science-style projects that can capture information from the world around me....
+
+
+
+
+
diff --git a/public/tags/diy/index.xml b/public/tags/diy/index.xml
index b0ae1bd..8f926e6 100644
--- a/public/tags/diy/index.xml
+++ b/public/tags/diy/index.xml
@@ -6,7 +6,25 @@
Recent content in diy on Norm-working Packets 💾Hugo -- gohugo.ioen-us
- Thu, 01 Sep 2022 13:25:02 -0400
+ Wed, 04 Oct 2023 10:35:23 -0400
+
+ BirdNET-PI & HomeAssistant: Part 2
+ /posts/birdnet_homeassistant_part2.html
+ Wed, 04 Oct 2023 10:35:23 -0400
+
+ /posts/birdnet_homeassistant_part2.html
+ A Follow up from the previous post, this tutorial takes all the sensors we created and loads them into a beautiful dashboard!
+
+
+
+ Creating a BirdNetPi Dashboard in HomeAssistant - Part 1
+ /posts/birdnet_homeassistant.html
+ Sat, 30 Sep 2023 11:21:55 -0400
+
+ /posts/birdnet_homeassistant.html
+ Learn how to take BirdNET-Pi Detections to create and display entities in HomeAssistant.
+
+
My First Merged PR!
/posts/whiptail-first-merged-pr.html
diff --git a/public/tags/git.html b/public/tags/git.html
index f515ed6..a7b3dc5 100644
--- a/public/tags/git.html
+++ b/public/tags/git.html
@@ -85,11 +85,16 @@ if (!doNotTrack) {
Checking for Entities If you’re following up on this from my first post, you’ve already added your AppDaemon script and confirmed that the AppDaemon logs don’t show any errors. Now is the true test if it’s working: do you have the new sensors in HomeAssistant?!
+The best way to do this is by just type e from any screen in the HomeAssistant UI! That will bring up a list of entities....
+
+
+
+
+
@@ -106,7 +126,7 @@ if (!doNotTrack) {
This is Part One of a Two Part Series. You can find Part Two, here.
What you will need BirdNET-Pi HomeAssistant AppDaemon MQTT Broker (I use Mosquitto) Background In early 2023, at the height of the Raspberry Pi shortage I felt like a king with an extra Rpi laying around, not being used. I’m a big fan of any sort of passive intake of information and had been looking around for various citizen science-style projects that can capture information from the world around me....
-
+
diff --git a/public/tags/homeassistant/index.xml b/public/tags/homeassistant/index.xml
index 65967a8..c79449b 100644
--- a/public/tags/homeassistant/index.xml
+++ b/public/tags/homeassistant/index.xml
@@ -6,11 +6,20 @@
Recent content in homeassistant on Norm-working Packets 💾Hugo -- gohugo.ioen-us
- Mon, 25 Sep 2023 12:51:55 -0400
+ Wed, 04 Oct 2023 10:35:23 -0400
+
+ BirdNET-PI & HomeAssistant: Part 2
+ /posts/birdnet_homeassistant_part2.html
+ Wed, 04 Oct 2023 10:35:23 -0400
+
+ /posts/birdnet_homeassistant_part2.html
+ A Follow up from the previous post, this tutorial takes all the sensors we created and loads them into a beautiful dashboard!
+
+
Creating a BirdNetPi Dashboard in HomeAssistant - Part 1
/posts/birdnet_homeassistant.html
- Mon, 25 Sep 2023 12:51:55 -0400
+ Sat, 30 Sep 2023 11:21:55 -0400/posts/birdnet_homeassistant.htmlLearn how to take BirdNET-Pi Detections to create and display entities in HomeAssistant.
diff --git a/public/tags/index.xml b/public/tags/index.xml
index eb67a35..8ad42f9 100644
--- a/public/tags/index.xml
+++ b/public/tags/index.xml
@@ -6,7 +6,43 @@
Recent content in Tags on Norm-working Packets 💾Hugo -- gohugo.ioen-us
- Fri, 22 Sep 2023 15:07:10 -0400
+ Wed, 04 Oct 2023 10:35:23 -0400
+
+ diy
+ /tags/diy.html
+ Wed, 04 Oct 2023 10:35:23 -0400
+
+ /tags/diy.html
+
+
+
+
+ homeassistant
+ /tags/homeassistant.html
+ Wed, 04 Oct 2023 10:35:23 -0400
+
+ /tags/homeassistant.html
+
+
+
+
+ selfhosted
+ /tags/selfhosted.html
+ Wed, 04 Oct 2023 10:35:23 -0400
+
+ /tags/selfhosted.html
+
+
+
+
+ python
+ /tags/python.html
+ Sat, 30 Sep 2023 11:21:55 -0400
+
+ /tags/python.html
+
+
+
backups
/tags/backups.html
@@ -34,15 +70,6 @@
-
- diy
- /tags/diy.html
- Thu, 01 Sep 2022 13:25:02 -0400
-
- /tags/diy.html
-
-
-
opensource
/tags/opensource.html
diff --git a/public/tags/opensource.html b/public/tags/opensource.html
index 276e743..049040e 100644
--- a/public/tags/opensource.html
+++ b/public/tags/opensource.html
@@ -85,11 +85,16 @@ if (!doNotTrack) {
This is Part One of a Two Part Series. You can find Part Two, here.
What you will need BirdNET-Pi HomeAssistant AppDaemon MQTT Broker (I use Mosquitto) Background In early 2023, at the height of the Raspberry Pi shortage I felt like a king with an extra Rpi laying around, not being used. I’m a big fan of any sort of passive intake of information and had been looking around for various citizen science-style projects that can capture information from the world around me....
Checking for Entities If you’re following up on this from my first post, you’ve already added your AppDaemon script and confirmed that the AppDaemon logs don’t show any errors. Now is the true test if it’s working: do you have the new sensors in HomeAssistant?!
+The best way to do this is by just type e from any screen in the HomeAssistant UI! That will bring up a list of entities....
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/tags/selfhosted/index.xml b/public/tags/selfhosted/index.xml
new file mode 100644
index 0000000..c95af21
--- /dev/null
+++ b/public/tags/selfhosted/index.xml
@@ -0,0 +1,20 @@
+
+
+
+ selfhosted on Norm-working Packets 💾
+ /tags/selfhosted.html
+ Recent content in selfhosted on Norm-working Packets 💾
+ Hugo -- gohugo.io
+ en-us
+ Wed, 04 Oct 2023 10:35:23 -0400
+
+ BirdNET-PI & HomeAssistant: Part 2
+ /posts/birdnet_homeassistant_part2.html
+ Wed, 04 Oct 2023 10:35:23 -0400
+
+ /posts/birdnet_homeassistant_part2.html
+ A Follow up from the previous post, this tutorial takes all the sensors we created and loads them into a beautiful dashboard!
+
+
+
+
diff --git a/public/tags/selfhosted/page/1.html b/public/tags/selfhosted/page/1.html
new file mode 100644
index 0000000..b8e2cb8
--- /dev/null
+++ b/public/tags/selfhosted/page/1.html
@@ -0,0 +1,10 @@
+
+
+
+ /tags/selfhosted.html
+
+
+
+
+
+
diff --git a/static/birdnet-homeassistant-part2.png b/static/birdnet-homeassistant-part2.png
new file mode 100644
index 0000000..aa70af1
Binary files /dev/null and b/static/birdnet-homeassistant-part2.png differ
diff --git a/static/hugo-nginx-trouble.png b/static/hugo-nginx-trouble.png
new file mode 100644
index 0000000..ea02b1d
Binary files /dev/null and b/static/hugo-nginx-trouble.png differ