12 Commits

Author SHA1 Message Date
Adrian Rumpold
35d5232d8e feat: Use syringe MDI icon for vaccination entity 2021-08-11 10:57:03 +02:00
Adrian Rumpold
1c3b0ae0b5 Merge pull request #3 from AdrianoKF/feature/vaccination-data
Crawling and parsing of vaccination data, see #2
2021-08-11 10:35:21 +02:00
Adrian Rumpold
d2e8f77725 docs: Update readme 2021-08-11 10:26:48 +02:00
Adrian Rumpold
92e99e03ef feat: Include ratio of at-least-once vaccinated persons 2021-08-11 10:26:18 +02:00
Adrian Rumpold
903a512f99 docs: Update readme 2021-08-11 10:21:34 +02:00
Adrian Rumpold
f385ee3a5a fix: Return vaccination percentage instead of ratio 2021-08-11 10:07:00 +02:00
Adrian Rumpold
573f91e2f9 chore: Bump manifest version 2021-08-11 09:47:20 +02:00
Adrian Rumpold
025a6475dd fix: Actually add vaccination entity to integratoin 2021-08-11 08:52:56 +02:00
Adrian Rumpold
216775e68f fix: Fix and disable some HACS validations 2021-08-11 08:39:56 +02:00
Adrian Rumpold
403efb937b feat(CI): Add HACS validation step to Github Actions 2021-08-11 08:32:51 +02:00
Adrian Rumpold
559a463140 feat: Add new entity for vaccination data to Home Asssistant integration 2021-08-11 08:28:24 +02:00
Adrian Rumpold
2f73be9010 chore: Refactor duplicated HTTP fetching code 2021-08-11 08:12:48 +02:00
6 changed files with 122 additions and 39 deletions

View File

@@ -50,3 +50,13 @@ jobs:
- name: Test with pytest
run: |
poetry run pytest
validate:
runs-on: "ubuntu-latest"
steps:
- uses: "actions/checkout@v2"
- name: HACS validation
uses: "hacs/action@main"
with:
category: "integration"
ignore: brands wheels

View File

@@ -2,7 +2,8 @@
## Adding to your dashboard
You can add an overview of the current infection numbers to your dashboard using the [multiple-entity-row](https://github.com/benct/lovelace-multiple-entity-row) card:
You can add an overview of the current infection and vaccination numbers to your dashboard
using the [multiple-entity-row](https://github.com/benct/lovelace-multiple-entity-row) card:
```yaml
type: entities
@@ -24,4 +25,25 @@ entities:
secondary_info:
attribute: incidence
unit: cases/100k
- type: custom:multiple-entity-row
entity: sensor.covid_19_vaccinations_augsburg
entities:
- attribute: ratio_vaccinated_once
name: Once
format: precision1
unit: '%'
- attribute: ratio_vaccinated_full
name: Fully
format: precision1
unit: '%'
- attribute: ratio_vaccinated_total
name: Total
format: precision1
unit: '%'
show_state: false
icon: mdi:needle
name: COVID-19 Vaccinations
secondary_info:
attribute: date
format: date
```

View File

@@ -12,7 +12,7 @@ if TYPE_CHECKING:
from homeassistant.core import HomeAssistant
from .const import DOMAIN
from .crawler import CovidCrawler, IncidenceData
from .crawler import CovidCrawler
_LOGGER = logging.getLogger(__name__)
@@ -67,9 +67,12 @@ async def get_coordinator(hass: HomeAssistant):
if DOMAIN in hass.data:
return hass.data[DOMAIN]
async def async_get_data() -> IncidenceData:
async def async_get_data() -> dict:
crawler = CovidCrawler(hass)
return await crawler.crawl_incidence()
return {
"incidence": await crawler.crawl_incidence(),
"vaccination": await crawler.crawl_vaccination(),
}
hass.data[DOMAIN] = DataUpdateCoordinator(
hass,

View File

@@ -62,6 +62,7 @@ class VaccinationData:
ratio_vaccinated_once: float = 0.0
ratio_vaccinated_full: float = 0.0
ratio_vaccinated_total: float = 0.0
class CovidCrawlerBase(ABC):
@@ -78,16 +79,9 @@ class CovidCrawler(CovidCrawlerBase):
def __init__(self, hass=None) -> None:
self.hass = hass
async def crawl_incidence(self) -> IncidenceData:
"""
Fetch COVID-19 infection data from the target website.
"""
async def _fetch(self, url: str) -> str:
"""Fetch a URL, using either the current Home Assistant instance or requests"""
_log.info("Fetching COVID-19 data update")
url = (
"https://www.augsburg.de/umwelt-soziales/gesundheit/coronavirus/fallzahlen"
)
if self.hass:
from homeassistant.helpers import aiohttp_client
@@ -99,6 +93,19 @@ class CovidCrawler(CovidCrawlerBase):
result = requests.get(url)
result.raise_for_status()
soup = BeautifulSoup(result.text, "html.parser")
return soup
async def crawl_incidence(self) -> IncidenceData:
"""
Fetch COVID-19 infection data from the target website.
"""
_log.info("Fetching COVID-19 data update")
url = (
"https://www.augsburg.de/umwelt-soziales/gesundheit/coronavirus/fallzahlen"
)
soup = await self._fetch(url)
match = soup.find(class_="frame--type-textpic")
text = match.p.text
@@ -155,20 +162,9 @@ class CovidCrawler(CovidCrawlerBase):
url = (
"https://www.augsburg.de/umwelt-soziales/gesundheit/coronavirus/impfzentrum"
)
soup = await self._fetch(url)
container_id = "c1088140"
if self.hass:
from homeassistant.helpers import aiohttp_client
result = await aiohttp_client.async_get_clientsession(self.hass).get(url)
soup = BeautifulSoup(await result.text(), "html.parser")
else:
import requests
result = requests.get(url)
result.raise_for_status()
soup = BeautifulSoup(result.text, "html.parser")
result = soup.find(id=container_id)
text = re.sub(r"\s+", " ", result.text)
regexes = [
@@ -199,8 +195,11 @@ class CovidCrawler(CovidCrawlerBase):
# https://www.augsburg.de/fileadmin/user_upload/buergerservice_rathaus/rathaus/statisiken_und_geodaten/statistiken/Monitoring/Demografiemonitoring_der_Stadt_Augsburg_2021.pdf
population = 299021
result.ratio_vaccinated_full = result.num_vaccinated_full / population
result.ratio_vaccinated_once = result.num_vaccinated_once / population
result.ratio_vaccinated_full = result.num_vaccinated_full / population * 100
result.ratio_vaccinated_once = result.num_vaccinated_once / population * 100
result.ratio_vaccinated_total = (
result.ratio_vaccinated_once + result.ratio_vaccinated_full
)
_log.debug(f"Result data: {result}")
return result

View File

@@ -1,9 +1,10 @@
{
"domain": "covid19_augsburg",
"name": "COVID-19 Augsburg",
"version": "0.1.0",
"version": "1.1.1",
"config_flow": true,
"documentation": "https://github.com/AdrianoKF/home-assistant-covid19-augsburg",
"issue_tracker": "https://github.com/AdrianoKF/home-assistant-covid19-augsburg/issues",
"requirements": ["beautifulsoup4==4.8.2"],
"dependencies": [],
"codeowners": ["@AdrianoKF"]

View File

@@ -1,3 +1,5 @@
from dataclasses import asdict
from homeassistant.helpers.entity import Entity
from . import get_coordinator
@@ -7,7 +9,12 @@ async def async_setup_entry(hass, _, async_add_entities):
"""Defer sensor setup to the shared sensor module."""
coordinator = await get_coordinator(hass)
async_add_entities([CoronaAugsburgSensor(coordinator)])
async_add_entities(
[
CoronaAugsburgSensor(coordinator),
CoronaAugsburgVaccinationSensor(coordinator),
]
)
class CoronaAugsburgSensor(Entity):
@@ -41,18 +48,59 @@ class CoronaAugsburgSensor(Entity):
@property
def state(self):
return self.coordinator.data.incidence
return self.coordinator.data["incidence"].incidence
@property
def device_state_attributes(self):
return {
"date": self.coordinator.data.date,
"incidence": self.coordinator.data.incidence,
"total_cases": self.coordinator.data.total_cases,
"num_dead": self.coordinator.data.num_dead,
"num_recovered": self.coordinator.data.num_recovered,
"num_infected": self.coordinator.data.num_infected,
}
data = self.coordinator.data["incidence"]
return asdict(data)
async def async_added_to_hass(self):
"""When entity is added to hass."""
self.coordinator.async_add_listener(self.async_write_ha_state)
async def async_will_remove_from_hass(self):
"""When entity will be removed from hass."""
self.coordinator.async_remove_listener(self.async_write_ha_state)
class CoronaAugsburgVaccinationSensor(Entity):
"""Representation of vaccination data for the city of Augsburg"""
def __init__(self, coordinator):
"""Initialize sensor."""
self.coordinator = coordinator
self._name = "COVID-19 Vaccinations Augsburg"
self._state = None
@property
def available(self):
return self.coordinator.last_update_success and self.coordinator.data
@property
def name(self):
return self._name
@property
def unique_id(self):
return self._name
@property
def icon(self):
return "mdi:needle"
@property
def unit_of_measurement(self):
return ""
@property
def state(self):
return self.coordinator.data["vaccination"].total_vaccinations
@property
def device_state_attributes(self):
data = self.coordinator.data["vaccination"]
return asdict(data)
async def async_added_to_hass(self):
"""When entity is added to hass."""