Integrate Silverbullet with Home Assistant (and more)

Hi All,

Quick one on something I have been working on. I have set up my quick note template to pull in weather info from my local home Assistant instance (but this could theoretically be used for all sorts of things).

You will need:

  • The address of your Home Assistance instance (mine is https as I use a reverse proxy yours may be http)
  • Your entitiyid (in my case weather.forecast_home)

It uses shell.run so is a bit unsafe but it is very useful and powerful so use caution.

In Home Assistant I set up a long lived access token by going to my profile > security > create token at the bottom. Keep this safe and don’t share it so it can be used later.

As I am using docker I then added it to the env variables as HA_TOKEN=<long_lived_token> .
I then created and mounted a scripts directory <-v /host/path/scripts:/scripts:ro>
Then I inserted a bash script called update-weatherpages.sh into the /scripts directory (with executable permissions).

#!/bin/bash
TOKEN="${HA_TOKEN}"
response=$(curl -s -X GET -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json"  https://<address of home assistant>/api/states/<entity>)
temperature=$(echo "$response" | grep -o '"temperature":[^,]*' | cut -d':' -f2)
echo "${temperature:-N/A} °C" | tr -d '\n' > /space/Weather/Temperature.md

Back in silverbullet I created the space-lua to call this: (Library/Custom/Update Weather)

local function runWeatherUpdate()
  local result = shell.run("/scripts/update-weatherpages.sh")
  local message
  if result then
    message = "[Weather Auto Update]\n" ..
      "stdout: " .. (result.stdout or "(none)") .. "\n" ..
      "stderr: " .. (result.stderr or "(none)") .. "\n" ..
      "exit code: " .. tostring(result.code or "nil")
  else
    message = "Failed to execute weather update script"
  end
  editor.flashNotification(message)
end
-- Command to run manually
command.define {
  name = "Weather Update Files",
  run = runWeatherUpdate
}
-- Scheduled event to run every hour
local updateInterval = 60
local lastUpdate = 0
event.listen {
  name = "cron:secondPassed",
  run = function()
    local now = os.time()
    if (now - lastUpdate)/60 >= updateInterval then
      lastUpdate = now
      runWeatherUpdate()
    end
  end
}

Once reloaded or restarted there will be a new command called Weather Update Files that you can manually run and this will also auto run every hour. More stuff can be added to the script and built up. This will then write the temperature to the file Weather/Temperature as defined in the bash script.

I then created a new page template for my quick notes to build this into new notes created automatically.

I tend to always work and new notes from a new note and then rename so the end result is that this begins to build up a lot of meta data on my notes.

Library/Custom/Page Templates/Custom Quick Note

---
command: Quick Note
key: "Alt-Shift-n"
suggestedName: "Inbox/${os.date('%Y-%m-%d/%H-%M-%S')}"
confirmName: false
tags: meta/template/page
---

---
time:      ${os.date("⠀%H-%M-%S")}
day:       ${os.date("⠀%A")}
month:     ${os.date("⠀%B")}
year:      ${os.date("⠀%Y")}
temp:       ${space.readPage("Weather/Temperature")}
---
#|^|

* 

Hopefully this makes a bit of sense but you could theoretically pull in prices for stocks and gpus etc or health metrics like sleep and steps quite easily if it is available assuming you can first get that data into Home Assistant or were comfortable getting it from other sources.

Using jq would make this much easier and more robust but I didn’t want to mess about with installing this but I would recommend!

Quick view of possible output below:

2 Likes

I love the idea of connecting Home Assistant to Silverbullet.

But instead of using a shell script I would recommend directly http.request’ing using the built in http.request function. which for HomeAssistant would look something like this to get the temperature from HomeAssistant weather forecast entity:

function getWeatherHASS()
       local HA_URL = "https://your.hass.url/api/states/"
       local ENTITY = "weather.forecast..."
       local HA_TOKEN = "YOUR_API_KEY"
    
       local url = HA_URL .. ENTITY
       local headers = {
            ["Authorization"] = "Bearer " .. HA_TOKEN,
            ["Content-Type"] = "application/json" 
           }
       local response = http.request(url,{method = "GET", headers = headers})
       local result = response.body.attributes.temperature
   return result .. "°C"
end  

of course this is just a proof of concept only.

and instead of storing the temperature in a page, why not use the datastore API and store the temperature in the clients storage and refresh only if it’s older than 60 min. this way you don’t need to run the request every time you need the temperature, you just fetch it from datastore, and if timestamp is older than 1h then and only then make a request to home assistant.

Here is an example of how to store weather information using the datastore:

if you need help with it just shout.

2 Likes

Ooh I like this much better! I had a feeling mine may have been a bit hacky! I will give it a try thanks for the tips :slight_smile:

1 Like