Dr. Smart Home Builds a Virtual Weather Station (and Teaches His Blinds Some Physics)

In my last blogpost of Dr. Smart Home Hacks, I showed how my 1Home Server KNX PRO learned to master my apartment’s “Night Scene” like a seasoned butler. Well, Dr. Smart Home didn’t stop there. Oh no. After conquering the evening routine, I set my sights on something a bit more… meteorological.

I live in a multi-apartment building which usually means no KNX (or any) weather station. To be completely honest - there is something on the roof which is controlling the roof window in common spaces but I it's impossible to access those readings. And if you’ve ever tried to run a halfway smart home without one, you know exactly how blind—pun absolutely intended—you feel. Temperature? Nada. Wind? Guesswork. Sun intensity? I stick my hand out the window and estimate. Not ideal.

Fortunately, as Aljaž Švigelj explains here, a decent virtual weather station can now be creating using the LUA block in the 1Home Automations editor. The entire ready-to-run example is already available inside the Lua editor’s Helper section.

A weather station example ready to use within the 1Home Automations

One click and boom—you suddenly have the following variables flowing into your 1Home system (and one "write to KNX" command away from having it in KNX as well):

  • outsideTemperature
  • windSpeed
  • windDirection
  • isSunny
  • isDay

For someone like me, who does not own a KNX weather station, this felt like cheating. I now had outside temperature available everywhere in the system—from heating logic to presence simulations to energy dashboards. Amazing.

You can write to KNX directly within LUA or you can only define outputs in LUA and then write those outputs to KNX by using an action block within the 1Home Automations editor

But of course I wouldn't be writing this article now if this wasn't just the intro to the real tinkering I did with the goal to be able to use the virtual weather station to control my blinds intelligently. For that I will have to modify my virtual weather station to give me more juice. With the current code I can protect my blinds against strong wind but I can't control my blinds to passively heat or prevent overheating of the apartment.

When You Have Three South-Facing Blinds and Zero Sun Data

I have three blinds facing south. In summer they should slam shut to prevent my apartment from turning into a convection oven or more accurately - to minimize the operation of our A/C unit. In winter they should politely open and let the sun warm the apartment for free—less heating, less energy, more smugness.

But the data I got from the basic example wasn’t enough. I needed something the KNX world calls lux.

Lux = light intensity

Lux = the thing that every weather station gives you

Lux = the thing that Open-Meteo absolutely does not give you.

So I did what any reasonable modern adult does when they’re stuck: I politely begged ChatGPT to help me. (As explained many times, I did some coding in the university but after that zero, thats why I need help from AI like many of you readers).

First, I gave it the pre-made example code and asked a simple question:

shortwave_radiation_sum

After a bit of thinking the machine produced a copy-pastable code, which I input in the LUA editor within the 1Home Automations, I pressed run aaaaaaaand .... it ran without errors and I got shortwave_radiation_sum as an output of the block. Step one done but how do I control shades with this now?

The Quest for a “Heat Index” (a.k.a. How to Teach Blinds Thermodynamics)

Next I asked ChatGPT the real question:

“OK now I need a variable which will tell me how much heat is coming in through my south windows—based on which I can lower the shades or lift them. Normally in KNX you have a weather station that gives you lux values. Maybe we do it the same way here?”

This gave the robot a pause for thought ... And then this pause seemed to stretch forever... When it finally responded, it delivered a surprisingly elegant idea:

Use hourly shortwave radiation → normalize to 0–1 → treat this as a “South Window Heat Index”.

  • 0 = no heat coming through windows
  • 1 = full hot summer sun blasting your living room
  • Anything in between = useful for automations
  • Add thresholds → lower or raise blinds
  • Add outdoor temperature → behave differently in summer vs. winter

This was actually better than relying on lux. Shortwave radiation is basically the actual heat from the sun that makes your apartment warm. Exactly what I needed.

So the robot spit out a nice tidy block of Lua code. I pasted it into the 1Home Lua editor. Aaaaaaaaaand… 💥 error.

A Dance of Errors, Screenshots, and Fixes

So I took a screenshot of the error message, sent it back to ChatGPT, and it gave me a revised code block. New paste → new error. Different screenshot → revised code. Another paste → another error. Screenshot → revised code.

We repeated this three or four times. (It almost felt like debugging with a very patient junior developer who neither eats nor sleeps.)

For example:

  • First error: I used a variable named error. Lua really didn’t like that.
  • Second error: Apparently the system didn’t enjoy anyone using os.date. (It protested like a toddler denied a cookie.)
  • Third error: Open-Meteo’s timestamps didn’t match until we indexed them properly.

Eventually the robot produced a final version that ran without a single error.

Add a log here, a threshold there, and—voilà!

I now had:

  • current shortwave radiation
  • daily radiation sum
  • a normalized 0–1 heat index
  • simple time-of-day correction
  • winter/summer behavior
  • shade down threshold
  • shade up threshold
  • a virtual weather station that actually understands heat flow

Not bad for an afternoon hacking session with a robot.

Dr. Smart Home’s New Trick: The Virtual Weather Station

So here we are.

My 1Home Server KNX PRO is now officially running a Virtual Weather Station powered by:

  • Lua
  • Open-Meteo
  • 1Home Automations
  • and a robot that wrote 90% of the code for me

The Code

If anyone would find a virtual weather station useful for themselves and doesn't want to do coding sessions with artificial smartyfullness - here is my code, anyone can use it, just copy paste and voila.

-- NOTE: This example uses Open-Meteo’s free API for personal, non-commercial use. 
-- If you use it commercially, please obtain a commercial API plan.

-- Fetch the Open-Meteo.com weather data for your location.
local url = string.format(
    "https://api.open-meteo.com/v1/forecast?latitude=%f&longitude=%f&current_weather=true&hourly=shortwave_radiation&daily=shortwave_radiation_sum&timezone=auto",
    location.latitude(), location.longitude()
)

-- Only use first two return values to avoid 'error' issues.
local response, statusCode = http.get(url, {
    responseBodyType = http.bodyType.JSON,
})

if statusCode ~= 200 then
    log.error("HTTP request failed, status code=%v", statusCode or -1)
    return
end

log.info("Weather response: %v", response)

----------------------------------------------------
-- Current weather
----------------------------------------------------
local outsideTemperature = response.current_weather.temperature
local windSpeed = response.current_weather.windspeed
local windDirectionDegrees = response.current_weather.winddirection
local isDay = response.current_weather.is_day == 1
local weatherCode = response.current_weather.weathercode
local isSunny = weatherCode < 3  -- 0,1,2 = clear / mainly clear / partly cloudy

----------------------------------------------------
-- Daily shortwave radiation sum (for info/logging)
----------------------------------------------------
local dailyShortwave = 0
if response.daily and response.daily.shortwave_radiation_sum then
    dailyShortwave = response.daily.shortwave_radiation_sum[1] or 0
end

----------------------------------------------------
-- Find current index in hourly data using time string
----------------------------------------------------
local currentRadiation = 0
local currentHour = 12   -- default / fallback
local currentTime = response.current_weather.time  -- e.g. "2025-11-17T16:45"

if currentTime then
    -- Parse hour from ISO time string ("YYYY-MM-DDTHH:MM")
    local hourStr = string.sub(currentTime, 12, 13)
    local parsedHour = tonumber(hourStr)
    if parsedHour ~= nil then
        currentHour = parsedHour
    end

    -- Find matching index in hourly.time array
    if response.hourly and response.hourly.shortwave_radiation and response.hourly.time then
        local idx = nil
        for i, t in ipairs(response.hourly.time) do
            if t == currentTime then
                idx = i
                break
            end
        end

        -- Fallback: if not found, use last value
        if not idx then
            idx = #response.hourly.shortwave_radiation
        end

        currentRadiation = response.hourly.shortwave_radiation[idx] or 0
    end
end

----------------------------------------------------
-- Compute "south window heat index"
-- 0.0 = no sun heat, 1.0 = strong sun (~>= 800 W/m²)
----------------------------------------------------
local MAX_REF_RADIATION = 800  -- typical strong sun value, tweak if needed
local sunIntensity = currentRadiation / MAX_REF_RADIATION
if sunIntensity > 1 then sunIntensity = 1 end
if sunIntensity < 0 then sunIntensity = 0 end

-- Only consider during day & when relatively sunny
if not isDay or not isSunny then
    sunIntensity = 0
end

-- Very simple approximation for south-facing using local hour
local orientationFactor = 1.0
if currentHour < 8 or currentHour > 18 then
    orientationFactor = 0.3
end

local southWindowHeatIndex = sunIntensity * orientationFactor

----------------------------------------------------
-- Logs
----------------------------------------------------
log.info("Outside temperature: %v", outsideTemperature)
log.info("Wind speed: %v", windSpeed)
log.info("Wind direction: %v", windDirectionDegrees)
log.info("Is sunny: %v", isSunny)
log.info("Is day: %v", isDay)
log.info("Daily shortwave sum (Wh/m²): %v", dailyShortwave)
log.info("Current shortwave radiation (W/m²): %v", currentRadiation)
log.info("South window heat index (0-1): %v", southWindowHeatIndex)

----------------------------------------------------
-- Example: write values to outputs
----------------------------------------------------
local err = OUTPUTS.Tout.set(outsideTemperature)
if err then log.error(err) end

if OUTPUTS.Radiation then
    local err2 = OUTPUTS.Radiation.set(currentRadiation)
    if err2 then log.error(err2) end
end

if OUTPUTS.SouthHeatIndex then
    local err3 = OUTPUTS.SouthHeatIndex.set(southWindowHeatIndex)
    if err3 then log.error(err3) end
end

----------------------------------------------------
-- Shade control logic (example)
-- Adjust thresholds to taste / test on site.
----------------------------------------------------
-- 0 = fully up, 1 = fully down (adapt to your real outputs)
local SHADE_DOWN_THRESHOLD  = 0.7  -- strong sun
local SHADE_UP_THRESHOLD    = 0.4  -- weak sun
local HOT_OUTSIDE_TEMP      = 22   -- above this we want to protect from heat
local COLD_OUTSIDE_TEMP     = 18   -- below this we may WANT heat gains

local shadeCommand = nil

if southWindowHeatIndex > SHADE_DOWN_THRESHOLD and outsideTemperature > HOT_OUTSIDE_TEMP then
    -- Too much heat coming in -> lower shades
    shadeCommand = 1
elseif southWindowHeatIndex < SHADE_UP_THRESHOLD or outsideTemperature < COLD_OUTSIDE_TEMP then
    -- Not much heat / it’s cold outside -> raise shades
    shadeCommand = 0
end

if shadeCommand ~= nil and OUTPUTS.SouthShade then
    local err4 = OUTPUTS.SouthShade.set(shadeCommand)
    if err4 then log.error(err4) end
    log.info("South shades command: %v", shadeCommand)
end 

What’s Next?

Right now, I’ve been running the entire thing in simulation mode within 1Home Automations. The final step is wiring the logic (by writing the resulting outputs to various group addresses with a "Write to KNX" action block) to the actual blinds and then fine tune the algorithm until it works perfectly in different weather scenarios. Not a small task and also not one where my best AI friend can help a lot. I'll just have to wait for different conditions and then tune the algorithm so it works great. I'll probably write more blogposts about my virtual weather station, when I actually see some results.

The official release of the FW containing (among other things) LUA is this week so also looking forward to what hacks and tricks the 1Home users pull out from their sleeves. I'll be super happy if you let me know about your own pains and how you solved them with LUA.

Dr. Smart Home, signing off — stay tuned for the next front of innovations sweeping through your smart home.