Skip to content

Instantly share code, notes, and snippets.

@martinharder
Last active October 10, 2022 12:52
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save martinharder/333300075dde7b31a28f1a5243d8f5b9 to your computer and use it in GitHub Desktop.
Save martinharder/333300075dde7b31a28f1a5243d8f5b9 to your computer and use it in GitHub Desktop.
COVID-19 Intensivbettenbelegung. Ein Widget für Scriptable
const newCasesApiUrl = `https://services7.arcgis.com/mOBPykOjAyBO2ZKk/arcgis/rest/services/DIVI_Intensivregister_Landkreise/FeatureServer/0/query?f=json&where=1%3D1&returnGeometry=false&spatialRel=esriSpatialRelIntersects&outFields=*&orderByFields=Anteil_betten_frei%20desc&resultOffset=0&resultRecordCount=4000&resultType=standard&cacheHint=true`;
/* Bundesland-ID:
Baden-Württemberg: 8
Bayern: 9
Berlin: 11
Brandenburg: 12
Bremen: 4
Hamburg: 2
Hessen: 6
Mecklenburg-Vorpommern: 13
Niedersachsen: 3
Nordrhein-Westfalen: 5
Rheinland-Pfalz: 7
Saarland: 10
Sachsen: 14
Sachsen-Anhalt: 15
Schleswig-Holstein: 1
Thüringen: 16
*/
const blTitle = {
1: 'SH',
2: 'HAMBURG',
3: 'NI',
4: 'BREMEN',
5: 'NRW',
6: 'HE',
7: 'RP',
8: 'BW',
9: 'BAYERN',
10: 'SL',
11: 'BERLIN',
12: 'BB',
13: 'MV',
14: 'SN',
15: 'ST',
16: 'TH'
}
const params = args.widgetParameter ? args.widgetParameter.split(',') : null;
const areaParam = params && params.length > 0 ? params[0].trim() : null;
const name = params && params.length === 2 ? params[1].trim() : null;
let bl = areaParam && +areaParam > 0 && +areaParam < 17 ? areaParam.toString() : null
bl = (bl && bl.length === 2 && bl.substr(0, 1) === '0') ? bl.substr(1,1) : bl
let lk = areaParam && +areaParam >= 01001 && +areaParam <= 16077 ? areaParam.toString() : null
lk = (lk && lk.length === 4) ? '0' + lk : lk
function calculateTotals(data) {
let betten_frei = 0
let betten_belegt = 0
let betten_gesamt = 0
let faelle_covid_aktuell = 0
let faelle_covid_aktuell_beatmet = 0
let blDataCount = 0
let county = null
if (lk) {
for (let i = 0; i < data.features.length; i++) {
const feature = data.features[i]
if (feature.attributes.AGS === lk) {
betten_gesamt = feature.attributes.betten_gesamt
betten_belegt = feature.attributes.betten_belegt
betten_frei = feature.attributes.betten_frei
faelle_covid_aktuell = feature.attributes.faelle_covid_aktuell
faelle_covid_aktuell_beatmet = feature.attributes.faelle_covid_aktuell_beatmet
county = feature.attributes.county
break;
}
}
} else {
data.features.forEach(feature => {
betten_gesamt += !bl || (bl && feature.attributes.BL_ID === bl) ? feature.attributes.betten_gesamt : 0
betten_belegt += !bl || (bl && feature.attributes.BL_ID === bl) ? feature.attributes.betten_belegt : 0
betten_frei += !bl || (bl && feature.attributes.BL_ID === bl) ? feature.attributes.betten_frei : 0
faelle_covid_aktuell += !bl || (bl && feature.attributes.BL_ID === bl) ? feature.attributes.faelle_covid_aktuell : 0
faelle_covid_aktuell_beatmet += !bl || (bl && feature.attributes.BL_ID === bl) ? feature.attributes.faelle_covid_aktuell_beatmet : 0
if (bl && feature.attributes.BL_ID === bl) {
blDataCount++
}
})
}
return {
betten_gesamt,
betten_belegt,
betten_frei,
faelle_covid_aktuell,
faelle_covid_aktuell_beatmet,
anteil_covid_betten: faelle_covid_aktuell > 0 && betten_belegt > 0 ? faelle_covid_aktuell * 100 / betten_belegt : 0,
anteil_beatmet: faelle_covid_aktuell_beatmet > 0 && faelle_covid_aktuell > 0 ? faelle_covid_aktuell_beatmet * 100 / faelle_covid_aktuell : 0,
freie_betten: betten_frei > 0 && betten_gesamt > 0 ? betten_frei * 100 / betten_gesamt : 0,
stand: data.features[0].attributes.daten_stand,
blDataCount,
county
}
}
let widget = await createWidget()
if (!config.runsInWidget) {
await widget.presentSmall()
}
Script.setWidget(widget)
Script.complete()
async function createWidget(items) {
let data, header, label
const widget = new ListWidget()
// fetch data
data = await new Request(newCasesApiUrl).loadJSON()
if (!data || !data.features || !data.features.length) {
const errorList = new ListWidget()
errorList.addText("Daten konnten nicht abgerufen werden.")
return errorList
}
const totals = calculateTotals(data)
if (bl && totals.blDataCount === 0) {
const errorList = new ListWidget()
errorList.addText(`Keine Daten für BL ${bl}`)
return errorList
}
if (lk && !totals.county) {
const errorList = new ListWidget()
errorList.addText(`Keine Daten für Landkreis ${lk}`)
return errorList
}
const headerTitle = name ? name : bl ? 'BL ' + blTitle[parseInt(args.widgetParameter)] : lk && totals.county ? totals.county : 'Intensivbetten'
header = widget.addText("🏥 " + headerTitle.toUpperCase())
header.centerAlignText()
header.font = Font.mediumSystemFont(10)
widget.addSpacer()
const infoText1 = widget.addText("COVID-19 Patienten".toUpperCase())
infoText1.centerAlignText()
infoText1.font = Font.mediumSystemFont(9)
label = widget.addText(totals.faelle_covid_aktuell.toLocaleString())
label.font = Font.mediumSystemFont(15)
label.centerAlignText()
const infoText2 = widget.addText(totals.anteil_covid_betten.toFixed(2) + "% der Betten")
infoText2.centerAlignText()
infoText2.font = Font.mediumSystemFont(9)
infoText2.textColor = Color.gray()
widget.addSpacer()
header = widget.addText("Davon beatmet".toUpperCase())
header.centerAlignText()
header.font = Font.mediumSystemFont(9)
label = widget.addText(totals.faelle_covid_aktuell_beatmet.toLocaleString())
label.centerAlignText()
label.font = Font.mediumSystemFont(15)
const infoText3 = widget.addText(totals.anteil_beatmet.toFixed(2) + "%")
infoText3.centerAlignText()
infoText3.font = Font.mediumSystemFont(9)
infoText3.textColor = Color.gray()
widget.addSpacer()
const infoText4 = widget.addText(totals.freie_betten.toFixed(2) + "% Betten frei")
infoText4.centerAlignText()
infoText4.font = Font.mediumSystemFont(10)
infoText4.textColor = totals.freie_betten > 25 ? Color.green() : totals.freie_betten > 10 ? Color.yellow() : Color.red()
const infoText5 = widget.addText(totals.betten_frei.toLocaleString() + ' von ' + totals.betten_gesamt.toLocaleString())
infoText5.centerAlignText()
infoText5.font = Font.mediumSystemFont(9)
infoText5.textColor = totals.freie_betten > 25 ? Color.green() : totals.freie_betten > 10 ? Color.yellow() : Color.red()
label = widget.addText("Stand: " + totals.stand.substr(0, 10))
label.centerAlignText()
label.font = Font.mediumSystemFont(8)
label.textColor = Color.gray()
return widget
}
@martinharder
Copy link
Author

@gunti-2020 ja sicher, ich werde das mit der Zeit noch erweitern. Hab da auch noch ein paar Ideen.

@AndyLiebe
Copy link

Super Ding! Danke Martin!

Mit welchen Args hätte ich die Möglichkeit Landkreise mit "Gemeindeschlüssel" zu suchen bzw. zu finden?

@martinharder
Copy link
Author

@AndyLiebe das ist noch nicht eingebaut. Ich schaue mir die Daten nochmal an und versuche das umzusetzen. Hab jetzt aber noch was anderes zu tun.

@martinharder
Copy link
Author

Die Daten sind so aufgebaut:
{ "OBJECTID":188, "AGS":"08135", "BL":"Baden-Württemberg", "BL_ID":"8", "county":"LK Heidenheim", "anzahl_standorte":1, "anzahl_meldebereiche":2, "betten_frei":6, "betten_belegt":16, "betten_gesamt":22, "Anteil_betten_frei":27.2727272727273, "faelle_covid_aktuell":1, "faelle_covid_aktuell_beatmet":0, "Anteil_covid_beatmet":0, "Anteil_COVID_betten":6.25, "daten_stand":"03.11.2020 12:15 Uhr", "Shape__Area":1436951157.27979, "Shape__Length":355965.452062642 }

Das heißt, man braucht den genauen Landkreisnamen. Ich denke, es wird ggf. besser möglich sein, wenn man die Requestparameter anpasst. Ich recherchiere mal, ob man da mit Gemeindeschlüsseln arbeiten kann.

@AndyLiebe
Copy link

Genau das "AGS":"08135" ist der Gemeindeschlüssel. Ich schau mal ob ich das raus bekomme.

@martinharder
Copy link
Author

Ja, dann kann ich nachher noch ein Update machen.

@caliban73
Copy link

J

Die Daten sind so aufgebaut:
{ "OBJECTID":188, "AGS":"08135", "BL":"Baden-Württemberg", "BL_ID":"8", "county":"LK Heidenheim", "anzahl_standorte":1, "anzahl_meldebereiche":2, "betten_frei":6, "betten_belegt":16, "betten_gesamt":22, "Anteil_betten_frei":27.2727272727273, "faelle_covid_aktuell":1, "faelle_covid_aktuell_beatmet":0, "Anteil_covid_beatmet":0, "Anteil_COVID_betten":6.25, "daten_stand":"03.11.2020 12:15 Uhr", "Shape__Area":1436951157.27979, "Shape__Length":355965.452062642 }

Das heißt, man braucht den genauen Landkreisnamen. Ich denke, es wird ggf. besser möglich sein, wenn man die Requestparameter anpasst. Ich recherchiere mal, ob man da mit Gemeindeschlüsseln arbeiten kann.

Hallo zusammen, ja Landkreise wäre vorteilhaft. IMO ist eine Zuordnung neben dem Gemeindeschlüssel auch über die eindeutige Objekt ID möglich.

Probiers ggf mal.

Grüße Caliban

@martinharder
Copy link
Author

Ich habe die Landkreisunterstützung eingebaut (siehe Beschreibung oben).

@caliban73
Copy link

caliban73 commented Nov 3, 2020

Ich habe die Landkreisunterstützung eingebaut (siehe Beschreibung oben).

@martinharder

Sehr gut. Sieht gut aus, vielen Dank.👍🏼

@martinharder
Copy link
Author

Neu hinzugefügt ist jetzt auch die absolute Anzahl von freien und allen Intensivbetten.

@peter-meyer
Copy link

Moin, moin!
Wo kann ich denn den Orts-Parameter "eingeben"?

@martinharder
Copy link
Author

Wenn man das Scriptable-Widget installiert, wählt man, welches Script ausgeführt werden soll und ganz unten können Parameter angegeben werden.

169D63AA-874D-40F3-BBC5-BADFBD6F1EC5

@meister-igi
Copy link

Danke für deine Mühe
Super Arbeit

@AndyLiebe
Copy link

Neu hinzugefügt ist jetzt auch die absolute Anzahl von freien und allen Intensivbetten.

Dankeschön für deine Arbeit! Super Sache!!!

@dennerforen
Copy link

Top update

@caliban73
Copy link

@martinharder

Vielen Dank an dieser Stelle auch nochmal von mir. Ich finde das Widget ist Dir gut gelungen.

Solltest Du den Code das nächste Mal wieder anfassen, wäre es zu überlegen, ob Du dann gleich das „Medium-Widget“ mit einbaust.

Dann könnte man die Situation im LK und BL oder D parallel betrachten.

@dennerforen
Copy link

Flannel ich auch den LK Namen ändern?

Ich habe LK Darmstadt - Dieburg und einmal ARGS Darmstadt Stadt.

Auf Meinem iPhone SE ist jeweils nur Darmstadt ... zu sehen.

@martinharder
Copy link
Author

Flannel ich auch den LK Namen ändern?

Ich habe LK Darmstadt - Dieburg und einmal ARGS Darmstadt Stadt.

Auf Meinem iPhone SE ist jeweils nur Darmstadt ... zu sehen.

Der Name stammt aus den Daten des DIVI-Intensivregisters. Dort ist pro AGS ein Datensatz vorhanden, in dem der Name des Landkreises angegeben ist. Diesen Namen benutze ich. Also kurzum: nein, das geht in diesem Widget nicht. Ich könnte das aber als einen zweiten Parameter einbauen oder die Schriftgröße je nach Länge des Namens anpassen. Schaue es mir für das nächste Update an.

@martinharder
Copy link
Author

@martinharder

Vielen Dank an dieser Stelle auch nochmal von mir. Ich finde das Widget ist Dir gut gelungen.

Solltest Du den Code das nächste Mal wieder anfassen, wäre es zu überlegen, ob Du dann gleich das „Medium-Widget“ mit einbaust.

Dann könnte man die Situation im LK und BL oder D parallel betrachten.

Das mit dem Medium-Widget habe ich mir auch schon überlegt. Der Aufwand dafür ist relativ hoch und bläht den Code ziemlich auf. Am Ende hat man fast das gleiche Ergebnis, wenn man zwei kleine Widgets nebeneinander mit unterschiedlichen Parametern benutzt.
Ein Medium-Widget würde ich mir vorstellen, wenn man es graphisch aufwertet und dann einen echten Mehrwert hat. Das kann ich bei mehr privater Zeit mal in Angriff nehmen, oder es findet sich nach der Veröffentlichung jemand, der einen Fork anbietet.

@dennerforen
Copy link

@martinharder

Als Parameter wäre mir lieber, noch kleinere Schrift ist auf se 1 eher nicht...

@martinharder
Copy link
Author

Hab es kurzfristig eingebaut. Nach der BL-ID oder LK-ID kann durch ein Komma getrennt ein Name angegeben werden.

@dennerforen
Copy link

Super, vielen Dank, funktioniert 👍😀

@dennerforen
Copy link

Hi Martin, Es stehen seit ein paar Tagen nur noch die Daten vom Vortag im Widget, nicht mehr Stunden aktuell.

@martinharder
Copy link
Author

Ich habe mir das Ergebnis angeschaut, was wir von der Schnittstelle bekommen. Da ist der Stand leider auch vom Vortag angegeben. Ich weiß leider nicht, woran das liegt, versuche es aber herauszufinden.

@dennerforen
Copy link

Danke. Dieses Widget bekommt die aktuellen Daten, vielleicht findest du ja da einen Hinweis.

https://gist.github.com/Keyes/7c357ae694d3762fcfbe3869c9e966ea

@lululasse
Copy link

Hi Martin, eigentlich müssten die Daten jetzt zumindest den Stand vom 16.12. anzeigen, oder? ich habe immer noch 15.12. Weißt Du was das Problem ist?

@martinharder
Copy link
Author

@dennerforen ich habe dort nach der Quelle nachgefragt, mal sehen. Aber seit heute scheinen die Daten wieder aktuell zu sein.
Hast du die Zahlen verglichen? Waren sie tatsächlich veraltet oder war der Zeitstempel nur falsch?

@lululasse da war es noch nicht Mittag ;) Sie aktualisieren die Daten immer erst gegen Mittag, manchmal auch später.

@dennerforen
Copy link

Ja, seltsam. Nein, die Zahlen hatte ich nicht verglichen, da habe ich mich vom Datum begleiten lassen.

Heute kommt es so einigermaßen hin, sind nur kleine Abweichungen. Wohl abhängig vom Aktualisierungszeitpunkt.
IMG_0887

@ChrisRo1987
Copy link

Vielen Dank für die tolle Arbeit!
Wäre es möglich ein Script zu erstellen welches die Auslastung in Zahlen zeigt, damit wüsste man schnell ab wann die Ampel Regeln aus der PK von 03.11.2021 in Bayern gelten!

Vielen Dank

@martinharder
Copy link
Author

Hallo ChrisRo1987, was genau meinst du mit Auslastung in Zahlen? Das sollte die letzte farbige Zeile in dem Widget darstellen).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment