Coronavirus disease 2019

COVID-19 is a contagious disease caused by the coronavirus SARS-CoV-2. In January 2020, the disease spread worldwide, resulting in the COVID-19 pandemic.

The symptoms of COVID‑19 can vary but often include fever,[7] fatigue, cough, breathing difficulties, loss of smell, and loss of taste.[8][9][10] Symptoms may begin one to fourteen days after exposure to the virus. At least a third of people who are infected do not develop noticeable symptoms.[11][12] Of those who develop symptoms noticeable enough to be classified as patients, most (81%) develop mild to moderate symptoms (up to mild pneumonia), while 14% develop severe symptoms (dyspnea, hypoxia, or more than 50% lung involvement on imaging), and 5% develop critical symptoms (respiratory failure, shock, or multiorgan dysfunction).[13] Older people have a higher risk of developing severe symptoms. Some complications result in death. Some people continue to experience a range of effects (long COVID) for months or years after infection, and damage to organs has been observed.[14] Multi-year studies on the long-term effects are ongoing.[15]

COVID‑19 transmission occurs when infectious particles are breathed in or come into contact with the eyes, nose, or mouth. The risk is highest when people are in close proximity, but small airborne particles containing the virus can remain suspended in the air and travel over longer distances, particularly indoors. Transmission can also occur when people touch their eyes, nose, or mouth after touching surfaces or objects that have been contaminated by the virus. People remain contagious for up to 20 days and can spread the virus even if they do not develop symptoms.[16]

Testing methods for COVID-19 to detect the virus’s nucleic acid include real-time reverse transcription polymerase chain reaction (RT‑PCR),[17][18] transcription-mediated amplification,[17][18][19] and reverse transcription loop-mediated isothermal amplification (RT‑LAMP)[17][18] from a nasopharyngeal swab.[20]

Several COVID-19 vaccines have been approved and distributed in various countries, many of which have initiated mass vaccination campaigns. Other preventive measures include physical or social distancing, quarantining, ventilation of indoor spaces, use of face masks or coverings in public, covering coughs and sneezes, hand washing, and keeping unwashed hands away from the face. While drugs have been developed to inhibit the virus, the primary treatment is still symptomatic, managing the disease through supportive care, isolation, and experimental measures.

Schnelles Deployen auf Raspberry Pi

Immer wieder dieses lästige Basissetup eines Raspberry Pis

TODO

Vorstellung Ansible

  • Connections / Hosts
  • Playbooks & Roles

Aber was ist mit meinen Passwörtern?

  • Vorstellung ansible_vault
  • Wie kann ansible_vault von mehreren Nutzern genutzt werden?

Lokale Entwicklerumgebung einrichten

  • Hosts
  • Secrets

OpenHAB3 mit Ansible installieren

  • Notwendige Roles

Mein Repository

  • Meinen Code-Tree teilen

Frische Luft ohne Eiszeit

Wer kennt nicht das Problem: man meint es gut und möchte lüften und dann vergisst man das offene Fenster. Kein Problem bei hohen Plus-Graden aber was ist im Winter bei Minus-Graden und laufender Heizung. Dies ist nicht nur eine Umweltsünde sondern macht die Wohnung auch ganz schön ungemütlich.

Aus diesem Grund habe ich mir die Zeit genommen um die bereits vorhandenen Fenstersensoren in ein Programm einzubinden, welches den Nutzer (also mich und alle im Haushalt) nach einer gewissen Zeit und vor allem periodisch über offene Fenster zu benachrichtigen.

Bridge openweathermap:weather-api:weather "OpenWeatherMap Account"
[
  apikey="...",
  refreshInterval=10,
  language="de"
]
{
    Thing weather-and-forecast local "Lokales Wetter"
    [
      location="48.118436,11.618119",
      forecastHours=0,
      forecastDays=0
    ]
    Thing onecall-history local "Lokale Historie"
    [
      location="48.118436,11.618119",
      forecastHours=0,
      forecastDays=0
    ]
    Thing onecall local "Lokales Wetter 2"
    [
      location="48.118436,11.618119",
      forecastHours=0,
      forecastDays=0
    ]
}
Switch contactWatchState "Fensterüberwachung" <window>
Switch contactWatchReset "Zurücksetzen" <button>

Number contactWatchTriggerTimer "Alarmtimer" <time>
Number contactWatchAlertSleep "Sleep between alerts in s" <time>

Number:Temperature contactWatchTriggerTemperature "Schwelle Außentemperatur [%.1f °C]" <temperatur>
Number:Temperature currentLocalTemperature "Aktuelle Temperatur [%.1f %unit%]" <temperature>
{
  channel="openweathermap:weather-and-forecast:weather:local:current#temperature"
}

Group ContactWatch "Gruppe zu überwachender Fenster"

Switch contactSimulation "Fenstersimulation" <window> (ContactWatch)
import java.util.Map
import java.time.Duration

val String loggerName = "ContactWatch"
var Map<String, ZonedDateTime> contactRegistry = newHashMap
var Map<String, ZonedDateTime> lastAlerts = newHashMap

rule "Register contact that got opened"
when
  Member of ContactWatch changed from CLOSED to OPEN or
  Member of ContactWatch changed from OFF to ON
then
  contactRegistry.put(triggeringItemName, new DateTimeType().getZonedDateTime())
  lastAlerts.remove(triggeringItemName)
  logError(loggerName, "Contacts {} now {}. {} contacts registered", triggeringItemName, newState, contactRegistry.size())
end

rule "Unregister contact that got closed"
when
  Member of ContactWatch changed from OPEN to CLOSED or
  Member of ContactWatch changed from ON to OFF
then
  contactRegistry.remove(triggeringItemName)
  lastAlerts.remove(triggeringItemName)
  logError(loggerName, "Contacts {} now {}. {} contacts registered", triggeringItemName, newState, contactRegistry.size())

end

rule "Reset contacts and system"
when
  Item contactWatchReset changed from OFF to ON
then
  logWarn(loggerName, "Reset requested. Will now reboot Max Cube and reset contacts")
  contactRegistry.clear()
  lastAlerts.clear()
  val maxCubeActions = getActions("max-cube", "max:bridge:cube")
  val Boolean success = maxCubeActions.reboot()
  logWarn(loggerName, "Reset requested with result {}", success)
  contactWatchReset.postUpdate(OFF)
end

rule "Check and alert opened contact state"
when
    Time cron "*/5 * * * * ?"
then
  val ZonedDateTime now = new DateTimeType().getZonedDateTime()
  val Integer triggerMinutes = (contactWatchTriggerTimer.state as Number)
  val Integer sleepSeconds = (contactWatchAlertSleep.state as Number)
  val Double triggerTemperature = (contactWatchTriggerTemperature.state as QuantityType<Number>).doubleValue
  val Double currentTemperature = (currentLocalTemperature.state as QuantityType<Number>).doubleValue
  val Boolean active = (contactWatchState.state == ON)
  logDebug(loggerName, "state={}; currentTemp={}; triggerTemp={}", active, currentTemperature, triggerTemperature)

  if (active && currentTemperature <=triggerTemperature)
  {
    for (Map.Entry<String, DateTimeType> openContact : contactRegistry.entrySet())
    {
      val Integer openSinceMinutes = Duration.between(openContact.getValue(), now).getSeconds() / 60
      logDebug(loggerName, "triggerMinutes={}; openSinceMinutes={}", triggerMinutes, openSinceMinutes)
      if (openSinceMinutes >= triggerMinutes)
      {
        var Boolean triggerAlert = true
        val lastAlert = lastAlerts.get(openContact.getKey())
        if (lastAlert !== null)
        {
          val Integer lastAlertBehindSeconds = Duration.between(lastAlert, now).getSeconds()
          if (lastAlertBehindSeconds < sleepSeconds)
            triggerAlert = false
        }
        if (triggerAlert)
        {
          lastAlerts.remove(openContact.getKey())
          lastAlerts.put(openContact.getKey(), now)
          val String msg = "Kontakt " + openContact.getKey() + " offen seit " + openSinceMinutes + " Minuten."
          sendNotification("michael@klemm-dachau.de", msg)
          logWarn(loggerName, msg)
        }
      }
      else
      {
        lastAlerts.remove(openContact.getKey())
      }
    }
   }
end

Raspberry Cluster mit einem Node

Ja ich weiß, ein Cluster besteht aus vielen Nodes. Nichtsdestotrotz ist das Konzept eines Clusters wirklich gut, so dass ich dies auch gerne auf einem einzigen Raspberry (aka Node) aufsetzte. Wer will kann das natürlich auch beliebig erweitern. Zunächst geht es mir dabei aber darum die Funktionsweise und die vorhandenen OpenSource-Werkzeuge vorzustellen.

Motivation

  • Sauberes setup
  • Wechsel zwischen Instanzen

Docker

Docker Swarm

Portainer

Traefik

Praxisteil

Stacks, Applications und Services anlegen und verwalten

MariaDB Image für den Raspberry bauen