Ecowitt API WX Info
Access your Ecowitt WX data from the API
| System | AWTRIX NG Scripts |
|---|---|
| Firmware | AWTRIX NG |
| Topic | Miscellaneous |
| Built by | r2k |
| File | KArfDmzG82D0.ax · 7.2 KB |
| Icons | — |
| Published | 15 Aug 2026 |
This project displays Ecowitt weather data on an AWTRIX NG. It retrieves the data directly from the Ecowitt API.
The app uses these icon IDs. These icons must be available on the AWTRIX.
Required IDs:
68435 Indoor Temperature
39041 Indoor Humidity
44092 Outdoor Temperature
2720 Rain
1153 Wind
2438 Measurement Time
Troubleshooting:
If only “API?” appears when using the Direct API option, application_key, api_key, or mac are not set.
If only “Weather n/a” appears, check the API response or feed.
If no icons appear, download the required IDs from the AWTRIX icon section.
If the script isn't running, check the message in the Scripts tab or in the AWTRIX console.
KArfDmzG82D0.ax
# @name Ecowitt API v2
# @desc Holt Ecowitt-Daten direkt von der API; OK wechselt die Seite
# @version 2.0
# @config application_key text "Application Key" default="" maxlen=64
# @config api_key text "API Key" default="" maxlen=64
# @config mac text "MAC-Adresse" default="" maxlen=32
# @config every number "Refresh" default=300 min=30 max=3600 unit=s
# @config show number "Seite" default=5 min=2 max=30 unit=s
# @config scroll_speed slider "Scrolltempo" default=80 min=20 max=200 unit=%
# @config temp_unit number "Temp Unit" default=1 min=1 max=2
# @config rain_unit number "Regen Unit" default=12 min=1 max=20
# @config wind_unit number "Wind Unit" default=7 min=1 max=20
import json
class EcowittApiV2
var url
var every
var show
var scroll_speed
var scroll_opts
var ticks
var in_flight
var items
var text_color
var page
var page_started
def init()
self.every = store.get("every")
self.show = store.get("show")
self.scroll_speed = store.get("scroll_speed")
self.scroll_opts = {"speed": clamp(self.scroll_speed, 20, 200)}
self.ticks = 0
self.in_flight = false
self.items = store.get("items")
self.text_color = settings.get("textColor")
self.page = 0
self.page_started = now_ms()
if self.text_color == nil
self.text_color = 0xFFFFFF
end
self.url = self.build_url()
if self.items == nil || size(self.items) == 0
self.items = [{"text": "Wetter n/a", "duration": 15000}]
end
end
def build_url()
var application_key = store.get("application_key")
var api_key = store.get("api_key")
var mac = store.get("mac")
if type(application_key) != "string" || application_key == ""
return nil
end
if type(api_key) != "string" || api_key == ""
return nil
end
if type(mac) != "string" || mac == ""
return nil
end
return "http://api.ecowitt.net/api/v3/device/real_time?" +
"application_key=" + application_key +
"&api_key=" + api_key +
"&mac=" + mac +
"&call_back=all" +
"&temp_unitid=" + str(store.get("temp_unit")) +
"&rainfall_unitid=" + str(store.get("rain_unit")) +
"&wind_speed_unitid=" + str(store.get("wind_unit"))
end
def clean_text(label)
if type(label) != "string"
return "-"
end
var m = re.match("^([-0-9.]+)℃$", label)
if m != nil
return m[1] + "C"
end
m = re.match("^([-0-9.]+)°C$", label)
if m != nil
return m[1] + "C"
end
return label
end
def format_now()
var h = hour()
var m = minute()
if h < 0 || m < 0
return nil
end
var mm = m < 10 ? "0" + str(m) : str(m)
return "Gemessen " + str(h) + ":" + mm
end
def make_item(text, icon_id, duration)
return {
"text": self.clean_text(text),
"icon": icon_id,
"duration": duration
}
end
def on_body(body, status)
self.in_flight = false
if body == nil || status < 200 || status >= 300
return
end
var root = json.load(body)
if !isinstance(root, map)
return
end
var data = root.find("data")
if !isinstance(data, map)
return
end
var indoor = data.find("indoor")
var outdoor = data.find("outdoor")
var wind = data.find("wind")
if !isinstance(indoor, map) || !isinstance(outdoor, map) || !isinstance(wind, map)
return
end
var temp_in = indoor.find("temperature")
var hum_in = indoor.find("humidity")
var temp_out = outdoor.find("temperature")
var wind_speed = wind.find("wind_speed")
if !isinstance(temp_in, map) || !isinstance(hum_in, map) || !isinstance(temp_out, map) || !isinstance(wind_speed, map)
return
end
var next_items = []
next_items.push(self.make_item(
str(temp_in.find("value", "-")) + str(temp_in.find("unit", "")),
"68435",
15000
))
next_items.push(self.make_item(
str(hum_in.find("value", "-")) + str(hum_in.find("unit", "")),
"39041",
15000
))
next_items.push(self.make_item(
str(temp_out.find("value", "-")) + str(temp_out.find("unit", "")),
"44092",
15000
))
var rainfall = data.find("rainfall_piezo")
if isinstance(rainfall, map)
var daily = rainfall.find("daily")
if isinstance(daily, map)
var rain_value = daily.find("value")
if num(rain_value) != nil && num(rain_value) > 0
next_items.push(self.make_item(
str(rain_value) + str(daily.find("unit", "")),
"2720",
15000
))
end
end
end
next_items.push(self.make_item(
str(wind_speed.find("value", "-")) + str(wind_speed.find("unit", "")),
"1153",
15000
))
var measured = self.format_now()
if measured != nil
next_items.push(self.make_item(measured, "2438", 15000))
end
if size(next_items) == 0
return
end
self.items = next_items
self.page = self.page % size(self.items)
store.set("items", self.items)
end
def loop()
if self.url == nil
return
end
if self.ticks <= 0
self.ticks = self.every
if !self.in_flight
self.in_flight = true
http.get(self.url, / b, st -> self.on_body(b, st))
end
end
self.ticks -= 1
end
def duration()
if self.items == nil || size(self.items) == 0
return 15000
end
return size(self.items) * clamp(self.show, 2, 30) * 1000
end
def on_button(btn)
if btn != "select" || self.items == nil || size(self.items) == 0
return
end
var now = now_ms()
var show_ms = clamp(self.show, 2, 30) * 1000
self.page = (self.page + int((now - self.page_started) / show_ms) + 1) % size(self.items)
self.page_started = now
end
def draw()
clear()
if self.url == nil
text(1, 6, "API?", self.text_color)
return
end
if self.items == nil || size(self.items) == 0
text(1, 6, "Wetter n/a", self.text_color)
return
end
var show_ms = clamp(self.show, 2, 30) * 1000
var index = (self.page + int((now_ms() - self.page_started) / show_ms)) % size(self.items)
var item = self.items[index]
if !isinstance(item, map)
text(1, 6, "Wetter n/a", self.text_color)
return
end
var label = item.find("text", "-")
var icon_name = item.find("icon")
var has_icon = type(icon_name) == "string" && icon_name != ""
if has_icon
if !icon(icon_name, 0, 0)
rect_fill(0, 0, 8, 8, 0x222222)
end
var avail = width() - 9
if text_ink_width(label) > avail
scroll_text(9, 6, avail, label, self.text_color, self.scroll_opts)
else
text(9 + (avail - text_ink_width(label)) / 2, 6, label, self.text_color)
end
return
end
if text_ink_width(label) > width()
scroll_text(label, self.text_color, self.scroll_opts)
else
text((width() - text_ink_width(label)) / 2, 6, label, self.text_color)
end
end
end
return EcowittApiV2()
Install it on your AWTRIX NG
Your browser writes the script straight to the device on your network. It joins the app rotation right away.
Some browsers refuse to talk to a device on your network from a public page. Download the flow and paste it into the Scripts tab of your device, or install it from a terminal:
More flows for AWTRIX NG Scripts or Miscellaneous
Something wrong with this flow? Report it.