[AirQuality] Tagging channels, prepared for Crowdin, dynamic channels (#11192)
* Adding semantic tags Adding alert level and code refined. Signed-off-by: Gaël L'hopital <gael@lhopital.org> * Commiting intermediate work Signed-off-by: Gaël L'hopital <gael@lhopital.org> * Complete review of the binding. Added measures for each pollutant. Added extensible channel for pollutant sensibility. Signed-off-by: clinique <gael@lhopital.org> * Finishing translation Signed-off-by: Gaël L'hopital <gael@lhopital.org> * One last code cleansing to be ready to push Signed-off-by: Gaël L'hopital <gael@lhopital.org> * Documentation updates Signed-off-by: Gaël L'hopital <gael@lhopital.org> * Spotless apply Signed-off-by: Gaël L'hopital <gael@lhopital.org> * Correcting conflicting file Signed-off-by: Gaël L'hopital <gael@lhopital.org> * Code review correction Signed-off-by: Gael L'hopital <gael@lhopital.org> * Introducing a bridge to Api Signed-off-by: clinique <gael@lhopital.org> * Code review correction Signed-off-by: clinique <gael@lhopital.org>
This commit is contained in:
parent
c79fd06256
commit
7bd71fdf12
|
@ -11,26 +11,32 @@ To use this binding, you first need to [register and get your API token](https:/
|
|||
|
||||
## Supported Things
|
||||
|
||||
There is exactly one supported thing type, which represents the air quality information for an observation location.
|
||||
It has the `aqi` id.
|
||||
Of course, you can add multiple Things, e.g. for measuring AQI for different locations.
|
||||
Bridge: The binding supports a bridge to connect to the [AQIcn.org service](https://aqicn.org). A bridge uses the thing ID "api".
|
||||
|
||||
Station: Represents the air quality information for an observation location.
|
||||
|
||||
Of course, you can add multiple Stations, e.g. for measuring AQI for different locations.
|
||||
|
||||
## Discovery
|
||||
|
||||
Local Air Quality can be autodiscovered based on system location.
|
||||
You will have complete default configuration with your apiKey.
|
||||
You will created a Bridge with your apiKey.
|
||||
|
||||
## Binding Configuration
|
||||
## Bridge Configuration
|
||||
|
||||
The binding has no configuration options, all configuration is done at Thing level.
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
The thing has a few configuration parameters:
|
||||
The bridge configuration only holds the api key :
|
||||
|
||||
| Parameter | Description |
|
||||
|-----------|-------------------------------------------------------------------------|
|
||||
| apiKey | Data-platform token to access the AQIcn.org service. Mandatory. |
|
||||
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
The 'Station' thing has a few configuration parameters:
|
||||
|
||||
| Parameter | Description |
|
||||
|-----------|-------------------------------------------------------------------------|
|
||||
| apikey | Data-platform token to access the AQIcn.org service. Mandatory. |
|
||||
| location | Geo coordinates to be considered by the service. |
|
||||
| stationId | Unique ID of the measuring station. |
|
||||
| refresh | Refresh interval in minutes. Optional, the default value is 60 minutes. |
|
||||
|
@ -45,59 +51,75 @@ For the location parameter, the following syntax is allowed (comma separated lat
|
|||
If you always want to receive data from specific station and you know its unique ID, you can enter it instead of the coordinates.
|
||||
|
||||
This `stationId` can be found by using the following link:
|
||||
https://api.waqi.info/search/?token=TOKEN&keyword=NAME, replacing TOKEN by your apikey and NAME by the station you are looking for.
|
||||
https://api.waqi.info/search/?token=TOKEN&keyword=NAME, replacing TOKEN by your apiKey and NAME by the station you are looking for.
|
||||
|
||||
### Thing properties
|
||||
|
||||
Once created, at first execution, the station's properties will be filled with informations gathered from the web service :
|
||||
|
||||
- Nearest measuring station location
|
||||
- Measuring station ID
|
||||
- Latitude/longitude of measuring station
|
||||
|
||||
|
||||
## Channels
|
||||
|
||||
The AirQuality information that is retrieved is available as these channels:
|
||||
The AirQuality information that is retrieved for a given is available as these channels:
|
||||
|
||||
### AQI Channels Group - Global Results
|
||||
|
||||
| Channel ID | Item Type | Description |
|
||||
|-----------------|----------------------|----------------------------------------------|
|
||||
| alert-level | Number | Alert level (*) associated to AQI Index. |
|
||||
| index | Number | Air Quality Index |
|
||||
| timestamp | DateTime | Observation date and time |
|
||||
| dominent | String | Dominent Pollutant |
|
||||
| icon | Image | Pictogram associated to alert-level |
|
||||
| color | Color | Color associated to alert level. |
|
||||
|
||||
### Weather Channels Group
|
||||
|
||||
| Channel ID | Item Type | Description |
|
||||
|-----------------|----------------------|----------------------------------------------|
|
||||
| aqiLevel | Number | Air Quality Index |
|
||||
| aqiColor | Color | Color associated to given AQI Index. |
|
||||
| aqiDescription | String | AQI Description |
|
||||
| locationName | String | Nearest measuring station location |
|
||||
| stationId | Number | Measuring station ID |
|
||||
| stationLocation | Location | Latitude/longitude of measuring station |
|
||||
| pm25 | Number | Fine particles pollution level (PM2.5) |
|
||||
| pm10 | Number | Coarse dust particles pollution level (PM10) |
|
||||
| o3 | Number | Ozone level (O3) |
|
||||
| no2 | Number | Nitrogen Dioxide level (NO2) |
|
||||
| co | Number | Carbon monoxide level (CO) |
|
||||
| so2 | Number | Sulfur dioxide level (SO2) |
|
||||
| observationTime | DateTime | Observation date and time |
|
||||
| temperature | Number:Temperature | Temperature in Celsius degrees |
|
||||
| pressure | Number:Pressure | Pressure level |
|
||||
| humidity | Number:Dimensionless | Humidity level |
|
||||
| dominentpol | String | Dominent Polutor |
|
||||
| dew-point | Number:Temperature | Dew point temperature |
|
||||
| wind-speed | Number:Speed | Wind speed |
|
||||
|
||||
`AQI Description` item provides a human-readable output that can be interpreted e.g. by MAP transformation.
|
||||
### Pollutants Channels Group
|
||||
|
||||
For each pollutant (PM25, PM10, O3, NO2, CO, SO2) , depending upon availability of the station,
|
||||
you will be provided with the following informations
|
||||
|
||||
| Channel ID | Item Type | Description |
|
||||
|-----------------|----------------------|----------------------------------------------|
|
||||
| value | Number:Density | Measured density of the pollutant |
|
||||
| index | Number | AQI Index of the single pollutant |
|
||||
| alert-level | Number | Alert level associate to the index |
|
||||
|
||||
|
||||
(*) The alert level is described by a color :
|
||||
|
||||
| Code | Color | Description |
|
||||
|------|--------|--------------------------------|
|
||||
| 0 | Green | Good |
|
||||
| 1 | Yellow | Moderate |
|
||||
| 2 | Orange | Unhealthy for Sensitive Groups |
|
||||
| 3 | Red | Unhealthy |
|
||||
| 4 | Purple | Very Unhealthy |
|
||||
| 5 | Maroon | Hazardous |
|
||||
|
||||
*Note that channels like* `pm25`, `pm10`, `o3`, `no2`, `co`, `so2` *can sometimes return* `UNDEF` *value due to the fact that some stations don't provide measurements for them.*
|
||||
|
||||
## Full Example
|
||||
|
||||
airquality.map:
|
||||
|
||||
```text
|
||||
-=-
|
||||
UNDEF=No data
|
||||
NULL=No data
|
||||
NO_DATA=No data
|
||||
GOOD=Good
|
||||
MODERATE=Moderate
|
||||
UNHEALTHY_FOR_SENSITIVE=Unhealthy for sensitive groups
|
||||
UNHEALTHY=Unhealthy
|
||||
VERY_UNHEALTHY=Very unhealthy
|
||||
HAZARDOUS=Hazardous
|
||||
```
|
||||
|
||||
airquality.things:
|
||||
|
||||
```java
|
||||
airquality:aqi:home "AirQuality" @ "Krakow" [ apikey="XXXXXXXXXXXX", location="50.06465,19.94498", refresh=60 ]
|
||||
airquality:aqi:warsaw "AirQuality in Warsaw" [ apikey="XXXXXXXXXXXX", location="52.22,21.01", refresh=60 ]
|
||||
airquality:aqi:brisbane "AirQuality in Brisbane" [ apikey="XXXXXXXXXXXX", stationId=5115 ]
|
||||
Bridge airquality:api:main "Bridge" [apiKey="xxxyyyzzz"] {
|
||||
station MyHouse "Krakow"[location="50.06465,19.94498", refresh=60]
|
||||
}
|
||||
```
|
||||
|
||||
airquality.items:
|
||||
|
@ -105,24 +127,19 @@ airquality.items:
|
|||
```java
|
||||
Group AirQuality <flow>
|
||||
|
||||
Number Aqi_Level "Air Quality Index" <flow> (AirQuality) { channel="airquality:aqi:home:aqiLevel" }
|
||||
String Aqi_Description "AQI Level [MAP(airquality.map):%s]" <flow> (AirQuality) { channel="airquality:aqi:home:aqiDescription" }
|
||||
Number Aqi_Level "Air Quality Index" <flow> (AirQuality) { channel="airquality:station:local:aqi#index" }
|
||||
Number Aqi_Pm25 "PM\u2082\u2085 Level" <line> (AirQuality) { channel="airquality:station:local:pm25#value" }
|
||||
Number Aqi_Pm10 "PM\u2081\u2080 Level" <line> (AirQuality) { channel="airquality:station:local:pm10#value" }
|
||||
Number Aqi_O3 "O\u2083 Level" <line> (AirQuality) { channel="airquality:station:local:o3#value" }
|
||||
Number Aqi_No2 "NO\u2082 Level" <line> (AirQuality) { channel="airquality:station:local:no2#value" }
|
||||
Number Aqi_Co "CO Level" <line> (AirQuality) { channel="airquality:station:local:co#value" }
|
||||
Number Aqi_So2 "SO\u2082 Level" <line> (AirQuality) { channel="airquality:station:local:so2#value" }
|
||||
|
||||
Number Aqi_Pm25 "PM\u2082\u2085 Level" <line> (AirQuality) { channel="airquality:aqi:home:pm25" }
|
||||
Number Aqi_Pm10 "PM\u2081\u2080 Level" <line> (AirQuality) { channel="airquality:aqi:home:pm10" }
|
||||
Number Aqi_O3 "O\u2083 Level" <line> (AirQuality) { channel="airquality:aqi:home:o3" }
|
||||
Number Aqi_No2 "NO\u2082 Level" <line> (AirQuality) { channel="airquality:aqi:home:no2" }
|
||||
Number Aqi_Co "CO Level" <line> (AirQuality) { channel="airquality:aqi:home:co" }
|
||||
Number Aqi_So2 "SO\u2082 Level" <line> (AirQuality) { channel="airquality:aqi:home:so2" }
|
||||
DateTime Aqi_ObservationTime "Time of observation [%1$tH:%1$tM]" <clock> (AirQuality) { channel="airquality:station:local:aqi#timestamp" }
|
||||
|
||||
String Aqi_LocationName "Measuring Location" <settings> (AirQuality) { channel="airquality:aqi:home:locationName" }
|
||||
Location Aqi_StationGeo "Station Location" <office> (AirQuality) { channel="airquality:aqi:home:stationLocation" }
|
||||
Number Aqi_StationId "Station ID" <pie> (AirQuality) { channel="airquality:aqi:home:stationId" }
|
||||
DateTime Aqi_ObservationTime "Time of observation [%1$tH:%1$tM]" <clock> (AirQuality) { channel="airquality:aqi:home:observationTime" }
|
||||
|
||||
Number:Temperature Aqi_Temperature "Temperature" <temperature> (AirQuality) { channel="airquality:aqi:home:temperature" }
|
||||
Number:Pressure Aqi_Pressure "Pressure" <pressure> (AirQuality) { channel="airquality:aqi:home:pressure" }
|
||||
Number:Dimensionless Aqi_Humidity "Humidity" <humidity> (AirQuality) { channel="airquality:aqi:home:humidity" }
|
||||
Number:Temperature Aqi_Temperature "Temperature" <temperature> (AirQuality) { channel="airquality:station:local:weather#temperature" }
|
||||
Number:Pressure Aqi_Pressure "Pressure" <pressure> (AirQuality) { channel="airquality:station:local:weather#pressure" }
|
||||
Number:Dimensionless Aqi_Humidity "Humidity" <humidity> (AirQuality) { channel="airquality:station:localweather#humidity" }
|
||||
```
|
||||
|
||||
airquality.sitemap:
|
||||
|
@ -143,7 +160,7 @@ sitemap airquality label="Air Quality" {
|
|||
Aqi_Description=="HAZARDOUS"="#7e0023",
|
||||
=="VERY_UNHEALTHY"="#660099",
|
||||
=="UNHEALTHY"="#cc0033",
|
||||
=="UNHEALTHY_FOR_SENSITIVE"="#ff9933",
|
||||
=="UNHEALTHY_FSG"="#ff9933",
|
||||
=="MODERATE"="#ffde33",
|
||||
=="GOOD"="#009966"
|
||||
]
|
||||
|
@ -159,16 +176,12 @@ sitemap airquality label="Air Quality" {
|
|||
}
|
||||
|
||||
Frame {
|
||||
Text item=Aqi_LocationName
|
||||
Text item=Aqi_ObservationTime
|
||||
Text item=Aqi_Temperature
|
||||
Text item=Aqi_Pressure
|
||||
Text item=Aqi_Humidity
|
||||
}
|
||||
|
||||
Frame label="Station Location" {
|
||||
Mapview item=Aqi_StationGeo height=10
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
@ -189,7 +202,7 @@ then
|
|||
hsb = "280,100,60"
|
||||
case "UNHEALTHY":
|
||||
hsb = "345,100,80"
|
||||
case "UNHEALTHY_FOR_SENSITIVE":
|
||||
case "UNHEALTHY_FSG":
|
||||
hsb = "30,80,100"
|
||||
case "MODERATE":
|
||||
hsb = "50,80,100"
|
||||
|
|
|
@ -12,74 +12,44 @@
|
|||
*/
|
||||
package org.openhab.binding.airquality.internal;
|
||||
|
||||
import static org.openhab.core.library.unit.MetricPrefix.HECTO;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.measure.Unit;
|
||||
import javax.measure.quantity.Dimensionless;
|
||||
import javax.measure.quantity.Pressure;
|
||||
import javax.measure.quantity.Temperature;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* The {@link AirQualityBinding} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Kuba Wolanin - Initial contribution
|
||||
* @author Łukasz Dywicki - Initial contribution
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AirQualityBindingConstants {
|
||||
|
||||
public static final String BINDING_ID = "airquality";
|
||||
private static final String BINDING_ID = "airquality";
|
||||
public static final String LOCAL = "local";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_AQI = new ThingTypeUID(BINDING_ID, "aqi");
|
||||
// List of thing properties
|
||||
public static final String ATTRIBUTIONS = "Attributions";
|
||||
public static final String DISTANCE = "Distance";
|
||||
|
||||
// List of all Channel groups id's
|
||||
public static final String AQI = "aqi";
|
||||
public static final String SENSITIVE = "sensitive-group";
|
||||
|
||||
// List of all Channel id's
|
||||
public static final String AQI = "aqiLevel";
|
||||
public static final String AQI_COLOR = "aqiColor";
|
||||
public static final String AQIDESCRIPTION = "aqiDescription";
|
||||
public static final String PM25 = "pm25";
|
||||
public static final String PM10 = "pm10";
|
||||
public static final String O3 = "o3";
|
||||
public static final String NO2 = "no2";
|
||||
public static final String CO = "co";
|
||||
public static final String SO2 = "so2";
|
||||
public static final String LOCATIONNAME = "locationName";
|
||||
public static final String STATIONLOCATION = "stationLocation";
|
||||
public static final String STATIONID = "stationId";
|
||||
public static final String OBSERVATIONTIME = "observationTime";
|
||||
public static final String INDEX = "index";
|
||||
public static final String VALUE = "value";
|
||||
public static final String ALERT_LEVEL = "alert-level";
|
||||
public static final String TEMPERATURE = "temperature";
|
||||
public static final String PRESSURE = "pressure";
|
||||
public static final String HUMIDITY = "humidity";
|
||||
public static final String DOMINENTPOL = "dominentpol";
|
||||
public static final String DEW_POINT = "dew-point";
|
||||
public static final String WIND_SPEED = "wind-speed";
|
||||
public static final String TIMESTAMP = "timestamp";
|
||||
public static final String DOMINENT = "dominent";
|
||||
public static final String ICON = "icon";
|
||||
public static final String COLOR = "color";
|
||||
|
||||
public static final State GOOD = new StringType("GOOD");
|
||||
public static final State MODERATE = new StringType("MODERATE");
|
||||
public static final State UNHEALTHY_FOR_SENSITIVE = new StringType("UNHEALTHY_FOR_SENSITIVE");
|
||||
public static final State UNHEALTHY = new StringType("UNHEALTHY");
|
||||
public static final State VERY_UNHEALTHY = new StringType("VERY_UNHEALTHY");
|
||||
public static final State HAZARDOUS = new StringType("HAZARDOUS");
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_AQI);
|
||||
public static final Set<String> SUPPORTED_CHANNEL_IDS = Stream.of(AQI, AQIDESCRIPTION, PM25, PM10, O3, NO2, CO, SO2,
|
||||
LOCATIONNAME, STATIONLOCATION, STATIONID, OBSERVATIONTIME, TEMPERATURE, PRESSURE, HUMIDITY)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// Units of measurement of the data delivered by the API
|
||||
public static final Unit<Temperature> API_TEMPERATURE_UNIT = SIUnits.CELSIUS;
|
||||
public static final Unit<Dimensionless> API_HUMIDITY_UNIT = Units.PERCENT;
|
||||
public static final Unit<Pressure> API_PRESSURE_UNIT = HECTO(SIUnits.PASCAL);
|
||||
// Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_STATION = new ThingTypeUID(BINDING_ID, "station");
|
||||
public static final ThingTypeUID BRIDGE_TYPE_API = new ThingTypeUID(BINDING_ID, "api");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.airquality.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* An exception that occurred while operating the binding
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AirQualityException extends Exception {
|
||||
private static final long serialVersionUID = -3398100220952729815L;
|
||||
private int statusCode = -1;
|
||||
|
||||
public AirQualityException(String message, Exception e) {
|
||||
super(message, e);
|
||||
}
|
||||
|
||||
public AirQualityException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public int getStatusCode() {
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getMessage() {
|
||||
String message = super.getMessage();
|
||||
return message == null ? null
|
||||
: String.format("Rest call failed: statusCode=%d, message=%s", statusCode, message);
|
||||
}
|
||||
}
|
|
@ -14,10 +14,15 @@ package org.openhab.binding.airquality.internal;
|
|||
|
||||
import static org.openhab.binding.airquality.internal.AirQualityBindingConstants.*;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.airquality.internal.handler.AirQualityHandler;
|
||||
import org.openhab.binding.airquality.internal.handler.AirQualityBridgeHandler;
|
||||
import org.openhab.binding.airquality.internal.handler.AirQualityStationHandler;
|
||||
import org.openhab.core.i18n.LocationProvider;
|
||||
import org.openhab.core.i18n.TimeZoneProvider;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
|
@ -27,23 +32,25 @@ import org.osgi.service.component.annotations.Activate;
|
|||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
/**
|
||||
* The {@link AirQualityHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
* The {@link AirQualityHandlerFactory} is responsible for creating thing and thing
|
||||
* handler.
|
||||
*
|
||||
* @author Kuba Wolanin - Initial contribution
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.airquality")
|
||||
@NonNullByDefault
|
||||
public class AirQualityHandlerFactory extends BaseThingHandlerFactory {
|
||||
private final Gson gson = new Gson();
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(BRIDGE_TYPE_API, THING_TYPE_STATION);
|
||||
|
||||
private final TimeZoneProvider timeZoneProvider;
|
||||
private final LocationProvider locationProvider;
|
||||
|
||||
@Activate
|
||||
public AirQualityHandlerFactory(final @Reference TimeZoneProvider timeZoneProvider) {
|
||||
public AirQualityHandlerFactory(final @Reference TimeZoneProvider timeZoneProvider,
|
||||
final @Reference LocationProvider locationProvider) {
|
||||
this.timeZoneProvider = timeZoneProvider;
|
||||
this.locationProvider = locationProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -55,10 +62,9 @@ public class AirQualityHandlerFactory extends BaseThingHandlerFactory {
|
|||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
|
||||
if (THING_TYPE_AQI.equals(thingTypeUID)) {
|
||||
return new AirQualityHandler(thing, gson, timeZoneProvider);
|
||||
}
|
||||
|
||||
return null;
|
||||
return THING_TYPE_STATION.equals(thingTypeUID)
|
||||
? new AirQualityStationHandler(thing, timeZoneProvider, locationProvider)
|
||||
: BRIDGE_TYPE_API.equals(thingTypeUID) ? new AirQualityBridgeHandler((Bridge) thing, locationProvider)
|
||||
: null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.airquality.internal.api;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.airquality.internal.AirQualityException;
|
||||
import org.openhab.binding.airquality.internal.api.dto.AirQualityData;
|
||||
import org.openhab.binding.airquality.internal.api.dto.AirQualityResponse;
|
||||
import org.openhab.binding.airquality.internal.api.dto.AirQualityResponse.ResponseStatus;
|
||||
import org.openhab.core.io.net.http.HttpUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
/**
|
||||
* The {@link ApiBridge} is the interface between handlers
|
||||
* and the actual web service
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ApiBridge {
|
||||
private static final Gson GSON = new Gson();
|
||||
private static final String URL = "http://api.waqi.info/feed/%query%/?token=%apiKey%";
|
||||
private static final int REQUEST_TIMEOUT_MS = (int) TimeUnit.SECONDS.toMillis(30);
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(ApiBridge.class);
|
||||
private final String apiKey;
|
||||
|
||||
public ApiBridge(String apiKey) {
|
||||
this.apiKey = apiKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build request URL from configuration data
|
||||
*
|
||||
* @return a valid URL for the aqicn.org service
|
||||
* @throws AirQualityException
|
||||
*/
|
||||
private String buildRequestURL(String key, int stationId, String location) {
|
||||
String geoStr = stationId != 0 ? String.format("@%d", stationId)
|
||||
: String.format("geo:%s",
|
||||
location.replace(" ", "").replace(",", ";").replace("\"", "").replace("'", "").trim());
|
||||
|
||||
return URL.replace("%apiKey%", key).replace("%query%", geoStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request new air quality data to the aqicn.org service
|
||||
*
|
||||
* @return an air quality data object mapping the JSON response
|
||||
* @throws AirQualityException
|
||||
*/
|
||||
public AirQualityData getData(int stationId, String location, int retryCounter) throws AirQualityException {
|
||||
String urlStr = buildRequestURL(apiKey, stationId, location);
|
||||
logger.debug("URL = {}", urlStr);
|
||||
|
||||
try {
|
||||
String response = HttpUtil.executeUrl("GET", urlStr, null, null, null, REQUEST_TIMEOUT_MS);
|
||||
logger.debug("aqiResponse = {}", response);
|
||||
AirQualityResponse result = GSON.fromJson(response, AirQualityResponse.class);
|
||||
if (result != null && result.getStatus() == ResponseStatus.OK) {
|
||||
return result.getData();
|
||||
} else if (retryCounter == 0) {
|
||||
logger.debug("Error in aqicn.org, retrying once");
|
||||
return getData(stationId, location, retryCounter + 1);
|
||||
}
|
||||
throw new AirQualityException("Error in aqicn.org response: Missing data sub-object");
|
||||
} catch (IOException | JsonSyntaxException e) {
|
||||
throw new AirQualityException("Communication error", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.airquality.internal.api;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.library.types.HSBType;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* The {@link Appreciation} enum lists all possible appreciation
|
||||
* of the AQI Level associated with their standard color.
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum Appreciation {
|
||||
GOOD(HSBType.fromRGB(0, 228, 0)),
|
||||
MODERATE(HSBType.fromRGB(255, 255, 0)),
|
||||
UNHEALTHY_FSG(HSBType.fromRGB(255, 126, 0)),
|
||||
UNHEALTHY(HSBType.fromRGB(255, 0, 0)),
|
||||
VERY_UNHEALTHY(HSBType.fromRGB(143, 63, 151)),
|
||||
HAZARDOUS(HSBType.fromRGB(126, 0, 35));
|
||||
|
||||
private HSBType color;
|
||||
|
||||
Appreciation(HSBType color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public State getColor() {
|
||||
return color;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.airquality.internal.api;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link ConcentrationRange} is responsible to store the range of
|
||||
* a given physical measure associated with the corresponding AQI
|
||||
* index.
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ConcentrationRange {
|
||||
private final double min;
|
||||
private final double span;
|
||||
private final Index index;
|
||||
|
||||
ConcentrationRange(double min, double max, Index index) {
|
||||
this.min = min;
|
||||
this.span = max - min;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
/*
|
||||
* Computes the concentration corresponding to the index
|
||||
* if contained in the range
|
||||
*
|
||||
* @return : a physical concentration or -1 if not in range
|
||||
*/
|
||||
double getConcentration(double idx) {
|
||||
return index.contains(idx) ? span / index.getSpan() * (idx - index.getMin()) + min : -1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.airquality.internal.api;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link Index} enum lists standard ranges of AQI indices
|
||||
* along with their appreciation category.
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum Index {
|
||||
ZERO(0, 50, Appreciation.GOOD),
|
||||
FIFTY(51, 100, Appreciation.MODERATE),
|
||||
ONE_HUNDRED(101, 150, Appreciation.UNHEALTHY_FSG),
|
||||
ONE_HUNDRED_FIFTY(151, 200, Appreciation.UNHEALTHY),
|
||||
TWO_HUNDRED(201, 300, Appreciation.VERY_UNHEALTHY),
|
||||
THREE_HUNDRED(301, 400, Appreciation.HAZARDOUS),
|
||||
FOUR_HUNDRED(401, 500, Appreciation.HAZARDOUS);
|
||||
|
||||
private double min;
|
||||
private double max;
|
||||
private Appreciation category;
|
||||
|
||||
Index(double min, double max, Appreciation category) {
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
public double getMin() {
|
||||
return min;
|
||||
}
|
||||
|
||||
public double getSpan() {
|
||||
return max - min;
|
||||
}
|
||||
|
||||
boolean contains(double idx) {
|
||||
return min <= idx && idx <= max;
|
||||
}
|
||||
|
||||
public static @Nullable Index find(double idx) {
|
||||
return Stream.of(Index.values()).filter(i -> i.contains(idx)).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
public Appreciation getCategory() {
|
||||
return category;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.airquality.internal.api;
|
||||
|
||||
import static org.openhab.binding.airquality.internal.api.Index.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.measure.Unit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
|
||||
/**
|
||||
* The {@link Pollutant} enum lists all measures
|
||||
* of the AQI Level associated with their standard color.
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum Pollutant {
|
||||
PM25(Units.MICROGRAM_PER_CUBICMETRE, 1,
|
||||
Set.of(SensitiveGroup.RESPIRATORY, SensitiveGroup.HEART, SensitiveGroup.ELDERLY, SensitiveGroup.CHILDREN),
|
||||
new ConcentrationRange(0, 12, ZERO), new ConcentrationRange(12.1, 35.4, FIFTY),
|
||||
new ConcentrationRange(35.5, 55.4, ONE_HUNDRED), new ConcentrationRange(55.5, 150.4, ONE_HUNDRED_FIFTY),
|
||||
new ConcentrationRange(150.5, 250.4, TWO_HUNDRED), new ConcentrationRange(250.5, 350.4, THREE_HUNDRED),
|
||||
new ConcentrationRange(350.5, 500.4, FOUR_HUNDRED)),
|
||||
PM10(Units.MICROGRAM_PER_CUBICMETRE, 0, Set.of(SensitiveGroup.RESPIRATORY), new ConcentrationRange(0, 54, ZERO),
|
||||
new ConcentrationRange(55, 154, FIFTY), new ConcentrationRange(155, 254, ONE_HUNDRED),
|
||||
new ConcentrationRange(255, 354, ONE_HUNDRED_FIFTY), new ConcentrationRange(355, 424, TWO_HUNDRED),
|
||||
new ConcentrationRange(425, 504, THREE_HUNDRED), new ConcentrationRange(505, 604, FOUR_HUNDRED)),
|
||||
NO2(Units.PARTS_PER_BILLION, 0,
|
||||
Set.of(SensitiveGroup.ASTHMA, SensitiveGroup.RESPIRATORY, SensitiveGroup.ELDERLY, SensitiveGroup.CHILDREN),
|
||||
new ConcentrationRange(0, 53, ZERO), new ConcentrationRange(54, 100, FIFTY),
|
||||
new ConcentrationRange(101, 360, ONE_HUNDRED), new ConcentrationRange(361, 649, ONE_HUNDRED_FIFTY),
|
||||
new ConcentrationRange(650, 1249, TWO_HUNDRED), new ConcentrationRange(1250, 1649, THREE_HUNDRED),
|
||||
new ConcentrationRange(1650, 2049, FOUR_HUNDRED)),
|
||||
SO2(Units.PARTS_PER_BILLION, 0, Set.of(SensitiveGroup.ASTHMA), new ConcentrationRange(0, 35, ZERO),
|
||||
new ConcentrationRange(36, 75, FIFTY), new ConcentrationRange(76, 185, ONE_HUNDRED),
|
||||
new ConcentrationRange(186, 304, ONE_HUNDRED_FIFTY), new ConcentrationRange(305, 604, TWO_HUNDRED),
|
||||
new ConcentrationRange(605, 804, THREE_HUNDRED), new ConcentrationRange(805, 1004, FOUR_HUNDRED)),
|
||||
CO(Units.PARTS_PER_BILLION, 1, Set.of(SensitiveGroup.HEART), new ConcentrationRange(0, 4.4, ZERO),
|
||||
new ConcentrationRange(4.5, 9.4, FIFTY), new ConcentrationRange(9.5, 12.4, ONE_HUNDRED),
|
||||
new ConcentrationRange(12.5, 15.4, ONE_HUNDRED_FIFTY), new ConcentrationRange(15.5, 30.4, TWO_HUNDRED),
|
||||
new ConcentrationRange(30.5, 40.4, THREE_HUNDRED), new ConcentrationRange(40.5, 50.4, FOUR_HUNDRED)),
|
||||
O3(Units.PARTS_PER_BILLION, 3, Set.of(SensitiveGroup.CHILDREN, SensitiveGroup.ASTHMA),
|
||||
new ConcentrationRange(0, 54, ZERO), new ConcentrationRange(55, 124, FIFTY),
|
||||
new ConcentrationRange(125, 164, ONE_HUNDRED), new ConcentrationRange(165, 204, ONE_HUNDRED_FIFTY),
|
||||
new ConcentrationRange(205, 404, TWO_HUNDRED), new ConcentrationRange(405, 504, THREE_HUNDRED),
|
||||
new ConcentrationRange(505, 604, FOUR_HUNDRED));
|
||||
|
||||
public static enum SensitiveGroup {
|
||||
RESPIRATORY,
|
||||
HEART,
|
||||
ELDERLY,
|
||||
CHILDREN,
|
||||
ASTHMA;
|
||||
}
|
||||
|
||||
public final Set<SensitiveGroup> sensitiveGroups;
|
||||
private final Unit<?> unit;
|
||||
private final Set<ConcentrationRange> breakpoints;
|
||||
private final int scale;
|
||||
|
||||
Pollutant(Unit<?> unit, int scale, Set<SensitiveGroup> groups, ConcentrationRange... concentrations) {
|
||||
this.sensitiveGroups = groups;
|
||||
this.unit = unit;
|
||||
this.breakpoints = Set.of(concentrations);
|
||||
this.scale = scale;
|
||||
}
|
||||
|
||||
public State toQuantity(double idx) {
|
||||
for (ConcentrationRange concentration : breakpoints) {
|
||||
double equivalent = concentration.getConcentration(idx);
|
||||
if (equivalent != -1) {
|
||||
return new QuantityType<>(BigDecimal.valueOf(equivalent).setScale(scale, RoundingMode.HALF_UP), unit);
|
||||
}
|
||||
}
|
||||
return UnDefType.UNDEF;
|
||||
}
|
||||
}
|
|
@ -10,9 +10,8 @@
|
|||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.airquality.internal.json;
|
||||
package org.openhab.binding.airquality.internal.api.dto;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -20,17 +19,16 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
|||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link AirQualityJsonCity} is responsible for storing
|
||||
* The {@link AirQualityCity} is responsible for storing
|
||||
* the "city" node from the waqi.org JSON response
|
||||
*
|
||||
* @author Kuba Wolanin - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AirQualityJsonCity {
|
||||
|
||||
public class AirQualityCity {
|
||||
private String name = "";
|
||||
private @Nullable String url;
|
||||
private List<Double> geo = new ArrayList<>();
|
||||
private List<Double> geo = List.of();
|
||||
|
||||
public String getName() {
|
||||
return name;
|
|
@ -10,32 +10,30 @@
|
|||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.airquality.internal.json;
|
||||
package org.openhab.binding.airquality.internal.api.dto;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.airquality.internal.api.Pollutant;
|
||||
|
||||
/**
|
||||
* The {@link AirQualityJsonData} is responsible for storing
|
||||
* The {@link AirQualityData} is responsible for storing
|
||||
* the "data" node from the waqi.org JSON response
|
||||
*
|
||||
* @author Kuba Wolanin - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AirQualityJsonData {
|
||||
|
||||
public class AirQualityData {
|
||||
private int aqi;
|
||||
private int idx;
|
||||
|
||||
private @NonNullByDefault({}) AirQualityJsonTime time;
|
||||
private @NonNullByDefault({}) AirQualityJsonCity city;
|
||||
private List<Attribute> attributions = new ArrayList<>();
|
||||
private Map<String, AirQualityValue> iaqi = new HashMap<>();
|
||||
private @NonNullByDefault({}) AirQualityTime time;
|
||||
private @NonNullByDefault({}) AirQualityCity city;
|
||||
private List<Attribution> attributions = List.of();
|
||||
private Map<String, AirQualityValue> iaqi = Map.of();
|
||||
private String dominentpol = "";
|
||||
|
||||
/**
|
||||
|
@ -61,7 +59,7 @@ public class AirQualityJsonData {
|
|||
*
|
||||
* @return {AirQualityJsonTime}
|
||||
*/
|
||||
public AirQualityJsonTime getTime() {
|
||||
public AirQualityTime getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
|
@ -70,20 +68,18 @@ public class AirQualityJsonData {
|
|||
*
|
||||
* @return {AirQualityJsonCity}
|
||||
*/
|
||||
public AirQualityJsonCity getCity() {
|
||||
public AirQualityCity getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects a list of attributions (vendors making data available)
|
||||
* and transforms it into readable string.
|
||||
* Currently displayed in Thing Status description when ONLINE
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
public String getAttributions() {
|
||||
String attributionsString = attributions.stream().map(Attribute::getName).collect(Collectors.joining(", "));
|
||||
return "Attributions : " + attributionsString;
|
||||
return attributions.stream().map(Attribution::getName).collect(Collectors.joining(", "));
|
||||
}
|
||||
|
||||
public String getDominentPol() {
|
||||
|
@ -92,9 +88,10 @@ public class AirQualityJsonData {
|
|||
|
||||
public double getIaqiValue(String key) {
|
||||
AirQualityValue result = iaqi.get(key);
|
||||
if (result != null) {
|
||||
return result.getValue();
|
||||
}
|
||||
return -1;
|
||||
return result != null ? result.getValue() : -1;
|
||||
}
|
||||
|
||||
public double getIaqiValue(Pollutant pollutant) {
|
||||
return getIaqiValue(pollutant.name().toLowerCase());
|
||||
}
|
||||
}
|
|
@ -10,20 +10,20 @@
|
|||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.airquality.internal.json;
|
||||
package org.openhab.binding.airquality.internal.api.dto;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link AirQualityJsonResponse} is the Java class used to map the JSON
|
||||
* The {@link AirQualityResponse} is the Java class used to map the JSON
|
||||
* response to the aqicn.org request.
|
||||
*
|
||||
* @author Kuba Wolanin - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AirQualityJsonResponse {
|
||||
public class AirQualityResponse {
|
||||
|
||||
public static enum ResponseStatus {
|
||||
NONE,
|
||||
|
@ -34,15 +34,13 @@ public class AirQualityJsonResponse {
|
|||
}
|
||||
|
||||
private ResponseStatus status = ResponseStatus.NONE;
|
||||
|
||||
@SerializedName("data")
|
||||
private @NonNullByDefault({}) AirQualityJsonData data;
|
||||
private @NonNullByDefault({}) AirQualityData data;
|
||||
|
||||
public ResponseStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public AirQualityJsonData getData() {
|
||||
public AirQualityData getData() {
|
||||
return data;
|
||||
}
|
||||
}
|
|
@ -10,32 +10,22 @@
|
|||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.airquality.internal.json;
|
||||
package org.openhab.binding.airquality.internal.api.dto;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeParseException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link AirQualityJsonTime} is responsible for storing
|
||||
* The {@link AirQualityTime} is responsible for storing
|
||||
* the "time" node from the waqi.org JSON response
|
||||
*
|
||||
* @author Kuba Wolanin - Initial contribution
|
||||
* @author Gaël L'hopital - Use ZonedDateTime instead of Calendar
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AirQualityJsonTime {
|
||||
|
||||
@SerializedName("s")
|
||||
private String dateString = "";
|
||||
|
||||
@SerializedName("tz")
|
||||
private String timeZone = "";
|
||||
|
||||
private String iso = "";
|
||||
public class AirQualityTime {
|
||||
private String iso = ""; // ISO representation of the timestamp, including TZ
|
||||
|
||||
/**
|
||||
* Get observation time
|
|
@ -10,24 +10,20 @@
|
|||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.airquality.internal.json;
|
||||
package org.openhab.binding.airquality.internal.api.dto;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Wrapper type around values reported by aqicn index values.
|
||||
*
|
||||
* @author Łukasz Dywicki - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AirQualityValue {
|
||||
|
||||
@SerializedName("v")
|
||||
private double value;
|
||||
class AirQualityValue {
|
||||
private double v;
|
||||
|
||||
public double getValue() {
|
||||
return value;
|
||||
return v;
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@
|
|||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.airquality.internal.json;
|
||||
package org.openhab.binding.airquality.internal.api.dto;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
@ -21,8 +21,7 @@ import org.eclipse.jdt.annotation.Nullable;
|
|||
* @author Łukasz Dywicki - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Attribute {
|
||||
|
||||
class Attribution {
|
||||
private @NonNullByDefault({}) String name;
|
||||
private @Nullable String url;
|
||||
private @Nullable String logo;
|
|
@ -10,10 +10,10 @@
|
|||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.airquality.internal;
|
||||
package org.openhab.binding.airquality.internal.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.airquality.internal.AirQualityException;
|
||||
|
||||
/**
|
||||
* The {@link AirQualityConfiguration} is the class used to match the
|
||||
|
@ -23,11 +23,19 @@ import org.eclipse.jdt.annotation.Nullable;
|
|||
*/
|
||||
@NonNullByDefault
|
||||
public class AirQualityConfiguration {
|
||||
|
||||
public static final String LOCATION = "location";
|
||||
public static final String STATION_ID = "stationId";
|
||||
|
||||
public String apikey = "";
|
||||
public String location = "";
|
||||
public @Nullable Integer stationId;
|
||||
public int stationId = 0;
|
||||
public int refresh = 60;
|
||||
|
||||
public void checkValid() throws AirQualityException {
|
||||
if (location.trim().isEmpty() && stationId == 0) {
|
||||
throw new AirQualityException("Either 'location' or 'stationId' is mandatory and must be configured");
|
||||
}
|
||||
if (refresh < 30) {
|
||||
throw new AirQualityException("Parameter 'refresh' must be at least 30 minutes");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.airquality.internal.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.airquality.internal.api.Pollutant.SensitiveGroup;
|
||||
|
||||
/**
|
||||
* The {@link SensitiveGroupConfiguration} is the class used to match the
|
||||
* sensitive-group channel configuration.
|
||||
*
|
||||
* @author Gaël L"hopital - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SensitiveGroupConfiguration {
|
||||
private String group = "RESPIRATORY";
|
||||
|
||||
public @Nullable SensitiveGroup asSensitiveGroup() {
|
||||
try {
|
||||
SensitiveGroup value = SensitiveGroup.valueOf(group);
|
||||
return value;
|
||||
} catch (IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,26 +13,24 @@
|
|||
package org.openhab.binding.airquality.internal.discovery;
|
||||
|
||||
import static org.openhab.binding.airquality.internal.AirQualityBindingConstants.*;
|
||||
import static org.openhab.binding.airquality.internal.AirQualityConfiguration.LOCATION;
|
||||
import static org.openhab.binding.airquality.internal.config.AirQualityConfiguration.LOCATION;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.airquality.internal.handler.AirQualityBridgeHandler;
|
||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.config.discovery.DiscoveryService;
|
||||
import org.openhab.core.i18n.LocationProvider;
|
||||
import org.openhab.core.library.types.PointType;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Modified;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -43,80 +41,60 @@ import org.slf4j.LoggerFactory;
|
|||
*/
|
||||
@Component(service = DiscoveryService.class, configurationPid = "discovery.airquality")
|
||||
@NonNullByDefault
|
||||
public class AirQualityDiscoveryService extends AbstractDiscoveryService {
|
||||
public class AirQualityDiscoveryService extends AbstractDiscoveryService implements ThingHandlerService {
|
||||
private static final int DISCOVER_TIMEOUT_SECONDS = 2;
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_STATION);
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(AirQualityDiscoveryService.class);
|
||||
|
||||
private static final int DISCOVER_TIMEOUT_SECONDS = 10;
|
||||
private static final int LOCATION_CHANGED_CHECK_INTERVAL = 60;
|
||||
|
||||
private final LocationProvider locationProvider;
|
||||
private @Nullable ScheduledFuture<?> discoveryJob;
|
||||
private @Nullable PointType previousLocation;
|
||||
private @Nullable LocationProvider locationProvider;
|
||||
private @Nullable AirQualityBridgeHandler bridgeHandler;
|
||||
|
||||
/**
|
||||
* Creates a AirQualityDiscoveryService with enabled autostart.
|
||||
*/
|
||||
@Activate
|
||||
public AirQualityDiscoveryService(@Reference LocationProvider locationProvider) {
|
||||
super(SUPPORTED_THING_TYPES, DISCOVER_TIMEOUT_SECONDS, true);
|
||||
this.locationProvider = locationProvider;
|
||||
public AirQualityDiscoveryService() {
|
||||
super(SUPPORTED_THING_TYPES_UIDS, DISCOVER_TIMEOUT_SECONDS, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate(@Nullable Map<String, Object> configProperties) {
|
||||
super.activate(configProperties);
|
||||
public void setThingHandler(@Nullable ThingHandler handler) {
|
||||
if (handler instanceof AirQualityBridgeHandler) {
|
||||
final AirQualityBridgeHandler bridgeHandler = (AirQualityBridgeHandler) handler;
|
||||
this.bridgeHandler = bridgeHandler;
|
||||
this.locationProvider = bridgeHandler.getLocationProvider();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Modified
|
||||
protected void modified(@Nullable Map<String, Object> configProperties) {
|
||||
super.modified(configProperties);
|
||||
public @Nullable ThingHandler getThingHandler() {
|
||||
return bridgeHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deactivate() {
|
||||
super.deactivate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startScan() {
|
||||
logger.debug("Starting Air Quality discovery scan");
|
||||
PointType location = locationProvider.getLocation();
|
||||
if (location == null) {
|
||||
logger.debug("LocationProvider.getLocation() is not set -> Will not provide any discovery results");
|
||||
return;
|
||||
}
|
||||
createResults(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startBackgroundDiscovery() {
|
||||
if (discoveryJob == null) {
|
||||
discoveryJob = scheduler.scheduleWithFixedDelay(() -> {
|
||||
PointType currentLocation = locationProvider.getLocation();
|
||||
if (currentLocation != null && !Objects.equals(currentLocation, previousLocation)) {
|
||||
logger.debug("Location has been changed from {} to {}: Creating new discovery results",
|
||||
previousLocation, currentLocation);
|
||||
createResults(currentLocation);
|
||||
previousLocation = currentLocation;
|
||||
}
|
||||
}, 0, LOCATION_CHANGED_CHECK_INTERVAL, TimeUnit.SECONDS);
|
||||
logger.debug("Scheduled Air Qualitylocation-changed job every {} seconds", LOCATION_CHANGED_CHECK_INTERVAL);
|
||||
}
|
||||
}
|
||||
|
||||
public void createResults(PointType location) {
|
||||
ThingUID localAirQualityThing = new ThingUID(THING_TYPE_AQI, LOCAL);
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put(LOCATION, String.format("%s,%s", location.getLatitude(), location.getLongitude()));
|
||||
thingDiscovered(DiscoveryResultBuilder.create(localAirQualityThing).withLabel("Local Air Quality")
|
||||
.withProperties(properties).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stopBackgroundDiscovery() {
|
||||
logger.debug("Stopping Air Quality background discovery");
|
||||
ScheduledFuture<?> job = this.discoveryJob;
|
||||
if (job != null && !job.isCancelled()) {
|
||||
if (job.cancel(true)) {
|
||||
discoveryJob = null;
|
||||
logger.debug("Stopped Air Quality background discovery");
|
||||
LocationProvider provider = locationProvider;
|
||||
if (provider != null) {
|
||||
PointType location = provider.getLocation();
|
||||
AirQualityBridgeHandler bridge = this.bridgeHandler;
|
||||
if (location == null || bridge == null) {
|
||||
logger.debug("LocationProvider.getLocation() is not set -> Will not provide any discovery results");
|
||||
return;
|
||||
}
|
||||
createResults(location, bridge.getThing().getUID());
|
||||
}
|
||||
}
|
||||
|
||||
public void createResults(PointType location, ThingUID bridgeUID) {
|
||||
ThingUID localAirQualityThing = new ThingUID(THING_TYPE_STATION, bridgeUID, LOCAL);
|
||||
thingDiscovered(DiscoveryResultBuilder.create(localAirQualityThing).withLabel("Local Air Quality")
|
||||
.withProperty(LOCATION, String.format("%s,%s", location.getLatitude(), location.getLongitude()))
|
||||
.withBridge(bridgeUID).build());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.airquality.internal.handler;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.airquality.internal.api.ApiBridge;
|
||||
import org.openhab.binding.airquality.internal.discovery.AirQualityDiscoveryService;
|
||||
import org.openhab.core.i18n.LocationProvider;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseBridgeHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||
import org.openhab.core.types.Command;
|
||||
|
||||
/**
|
||||
* The {@link AirQualityBridgeHandler} is responsible for handling communication
|
||||
* with the service via the API.
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AirQualityBridgeHandler extends BaseBridgeHandler {
|
||||
private final LocationProvider locationProvider;
|
||||
private @Nullable ApiBridge apiBridge;
|
||||
|
||||
public AirQualityBridgeHandler(Bridge bridge, LocationProvider locationProvider) {
|
||||
super(bridge);
|
||||
this.locationProvider = locationProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
String apiKey = (String) getConfig().get("apiKey");
|
||||
if (apiKey != null && apiKey.length() != 0) {
|
||||
apiBridge = new ApiBridge(apiKey);
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
apiBridge = null;
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/null-or-empty-api-key");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
// We do nothing
|
||||
}
|
||||
|
||||
public @Nullable ApiBridge getApiBridge() {
|
||||
return apiBridge;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Class<? extends ThingHandlerService>> getServices() {
|
||||
return Collections.singleton(AirQualityDiscoveryService.class);
|
||||
}
|
||||
|
||||
public LocationProvider getLocationProvider() {
|
||||
return locationProvider;
|
||||
}
|
||||
}
|
|
@ -1,285 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.airquality.internal.handler;
|
||||
|
||||
import static org.openhab.binding.airquality.internal.AirQualityBindingConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.airquality.internal.AirQualityConfiguration;
|
||||
import org.openhab.binding.airquality.internal.json.AirQualityJsonData;
|
||||
import org.openhab.binding.airquality.internal.json.AirQualityJsonResponse;
|
||||
import org.openhab.binding.airquality.internal.json.AirQualityJsonResponse.ResponseStatus;
|
||||
import org.openhab.core.i18n.TimeZoneProvider;
|
||||
import org.openhab.core.io.net.http.HttpUtil;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.HSBType;
|
||||
import org.openhab.core.library.types.PointType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
/**
|
||||
* The {@link AirQualityHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Kuba Wolanin - Initial contribution
|
||||
* @author Łukasz Dywicki - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AirQualityHandler extends BaseThingHandler {
|
||||
private static final String URL = "http://api.waqi.info/feed/%QUERY%/?token=%apikey%";
|
||||
private static final int REQUEST_TIMEOUT_MS = (int) TimeUnit.SECONDS.toMillis(30);
|
||||
private final Logger logger = LoggerFactory.getLogger(AirQualityHandler.class);
|
||||
private @Nullable ScheduledFuture<?> refreshJob;
|
||||
|
||||
private final Gson gson;
|
||||
|
||||
private int retryCounter = 0;
|
||||
private final TimeZoneProvider timeZoneProvider;
|
||||
|
||||
public AirQualityHandler(Thing thing, Gson gson, TimeZoneProvider timeZoneProvider) {
|
||||
super(thing);
|
||||
this.gson = gson;
|
||||
this.timeZoneProvider = timeZoneProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
logger.debug("Initializing Air Quality handler.");
|
||||
|
||||
AirQualityConfiguration config = getConfigAs(AirQualityConfiguration.class);
|
||||
logger.debug("config apikey = (omitted from logging)");
|
||||
logger.debug("config location = {}", config.location);
|
||||
logger.debug("config stationId = {}", config.stationId);
|
||||
logger.debug("config refresh = {}", config.refresh);
|
||||
|
||||
List<String> errorMsg = new ArrayList<>();
|
||||
|
||||
if (config.apikey.trim().isEmpty()) {
|
||||
errorMsg.add("Parameter 'apikey' is mandatory and must be configured");
|
||||
}
|
||||
if (config.location.trim().isEmpty() && config.stationId == null) {
|
||||
errorMsg.add("Parameter 'location' or 'stationId' is mandatory and must be configured");
|
||||
}
|
||||
if (config.refresh < 30) {
|
||||
errorMsg.add("Parameter 'refresh' must be at least 30 minutes");
|
||||
}
|
||||
|
||||
if (errorMsg.isEmpty()) {
|
||||
ScheduledFuture<?> job = this.refreshJob;
|
||||
if (job == null || job.isCancelled()) {
|
||||
refreshJob = scheduler.scheduleWithFixedDelay(this::updateAndPublishData, 0, config.refresh,
|
||||
TimeUnit.MINUTES);
|
||||
}
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, String.join(", ", errorMsg));
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAndPublishData() {
|
||||
retryCounter = 0;
|
||||
AirQualityJsonData aqiResponse = getAirQualityData();
|
||||
if (aqiResponse != null) {
|
||||
// Update all channels from the updated AQI data
|
||||
getThing().getChannels().stream().filter(channel -> isLinked(channel.getUID().getId())).forEach(channel -> {
|
||||
String channelId = channel.getUID().getId();
|
||||
State state = getValue(channelId, aqiResponse);
|
||||
updateState(channelId, state);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
logger.debug("Disposing the Air Quality handler.");
|
||||
ScheduledFuture<?> job = this.refreshJob;
|
||||
if (job != null && !job.isCancelled()) {
|
||||
job.cancel(true);
|
||||
refreshJob = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (command instanceof RefreshType) {
|
||||
updateAndPublishData();
|
||||
} else {
|
||||
logger.debug("The Air Quality binding is read-only and can not handle command {}", command);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build request URL from configuration data
|
||||
*
|
||||
* @return a valid URL for the aqicn.org service
|
||||
*/
|
||||
private String buildRequestURL() {
|
||||
AirQualityConfiguration config = getConfigAs(AirQualityConfiguration.class);
|
||||
|
||||
String location = config.location.trim();
|
||||
Integer stationId = config.stationId;
|
||||
|
||||
String geoStr = "geo:" + location.replace(" ", "").replace(",", ";").replace("\"", "").replace("'", "").trim();
|
||||
|
||||
String urlStr = URL.replace("%apikey%", config.apikey.trim());
|
||||
|
||||
return urlStr.replace("%QUERY%", stationId == null ? geoStr : "@" + stationId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request new air quality data to the aqicn.org service
|
||||
*
|
||||
* @param location geo-coordinates from config
|
||||
* @param stationId station ID from config
|
||||
* @return the air quality data object mapping the JSON response or null in case of error
|
||||
*/
|
||||
private @Nullable AirQualityJsonData getAirQualityData() {
|
||||
String errorMsg;
|
||||
|
||||
String urlStr = buildRequestURL();
|
||||
logger.debug("URL = {}", urlStr);
|
||||
|
||||
try {
|
||||
String response = HttpUtil.executeUrl("GET", urlStr, null, null, null, REQUEST_TIMEOUT_MS);
|
||||
logger.debug("aqiResponse = {}", response);
|
||||
AirQualityJsonResponse result = gson.fromJson(response, AirQualityJsonResponse.class);
|
||||
if (result.getStatus() == ResponseStatus.OK) {
|
||||
AirQualityJsonData data = result.getData();
|
||||
String attributions = data.getAttributions();
|
||||
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE, attributions);
|
||||
return data;
|
||||
} else {
|
||||
retryCounter++;
|
||||
if (retryCounter == 1) {
|
||||
logger.warn("Error in aqicn.org, retrying once");
|
||||
return getAirQualityData();
|
||||
}
|
||||
errorMsg = "Missing data sub-object";
|
||||
logger.warn("Error in aqicn.org response: {}", errorMsg);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
errorMsg = e.getMessage();
|
||||
} catch (JsonSyntaxException e) {
|
||||
errorMsg = "Configuration is incorrect";
|
||||
logger.warn("Error running aqicn.org request: {}", errorMsg);
|
||||
}
|
||||
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, errorMsg);
|
||||
return null;
|
||||
}
|
||||
|
||||
public State getValue(String channelId, AirQualityJsonData aqiResponse) {
|
||||
String[] fields = channelId.split("#");
|
||||
|
||||
switch (fields[0]) {
|
||||
case AQI:
|
||||
return new DecimalType(aqiResponse.getAqi());
|
||||
case AQIDESCRIPTION:
|
||||
return getAqiDescription(aqiResponse.getAqi());
|
||||
case PM25:
|
||||
case PM10:
|
||||
case O3:
|
||||
case NO2:
|
||||
case CO:
|
||||
case SO2:
|
||||
double value = aqiResponse.getIaqiValue(fields[0]);
|
||||
return value != -1 ? new DecimalType(value) : UnDefType.UNDEF;
|
||||
case TEMPERATURE:
|
||||
double temp = aqiResponse.getIaqiValue("t");
|
||||
return temp != -1 ? new QuantityType<>(temp, API_TEMPERATURE_UNIT) : UnDefType.UNDEF;
|
||||
case PRESSURE:
|
||||
double press = aqiResponse.getIaqiValue("p");
|
||||
return press != -1 ? new QuantityType<>(press, API_PRESSURE_UNIT) : UnDefType.UNDEF;
|
||||
case HUMIDITY:
|
||||
double hum = aqiResponse.getIaqiValue("h");
|
||||
return hum != -1 ? new QuantityType<>(hum, API_HUMIDITY_UNIT) : UnDefType.UNDEF;
|
||||
case LOCATIONNAME:
|
||||
return new StringType(aqiResponse.getCity().getName());
|
||||
case STATIONID:
|
||||
return new DecimalType(aqiResponse.getStationId());
|
||||
case STATIONLOCATION:
|
||||
return new PointType(aqiResponse.getCity().getGeo());
|
||||
case OBSERVATIONTIME:
|
||||
return new DateTimeType(
|
||||
aqiResponse.getTime().getObservationTime().withZoneSameLocal(timeZoneProvider.getTimeZone()));
|
||||
case DOMINENTPOL:
|
||||
return new StringType(aqiResponse.getDominentPol());
|
||||
case AQI_COLOR:
|
||||
return getAsHSB(aqiResponse.getAqi());
|
||||
default:
|
||||
return UnDefType.UNDEF;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interprets the current aqi value within the ranges;
|
||||
* Returns AQI in a human readable format
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public State getAqiDescription(int index) {
|
||||
if (index >= 300) {
|
||||
return HAZARDOUS;
|
||||
} else if (index >= 201) {
|
||||
return VERY_UNHEALTHY;
|
||||
} else if (index >= 151) {
|
||||
return UNHEALTHY;
|
||||
} else if (index >= 101) {
|
||||
return UNHEALTHY_FOR_SENSITIVE;
|
||||
} else if (index >= 51) {
|
||||
return MODERATE;
|
||||
} else if (index > 0) {
|
||||
return GOOD;
|
||||
}
|
||||
return UnDefType.UNDEF;
|
||||
}
|
||||
|
||||
private State getAsHSB(int index) {
|
||||
State state = getAqiDescription(index);
|
||||
if (state == HAZARDOUS) {
|
||||
return HSBType.fromRGB(343, 100, 49);
|
||||
} else if (state == VERY_UNHEALTHY) {
|
||||
return HSBType.fromRGB(280, 100, 60);
|
||||
} else if (state == UNHEALTHY) {
|
||||
return HSBType.fromRGB(345, 100, 80);
|
||||
} else if (state == UNHEALTHY_FOR_SENSITIVE) {
|
||||
return HSBType.fromRGB(30, 80, 100);
|
||||
} else if (state == MODERATE) {
|
||||
return HSBType.fromRGB(50, 80, 100);
|
||||
} else if (state == GOOD) {
|
||||
return HSBType.fromRGB(160, 100, 60);
|
||||
}
|
||||
return UnDefType.UNDEF;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,298 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2021 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.airquality.internal.handler;
|
||||
|
||||
import static org.openhab.binding.airquality.internal.AirQualityBindingConstants.*;
|
||||
import static org.openhab.core.library.unit.MetricPrefix.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.airquality.internal.AirQualityException;
|
||||
import org.openhab.binding.airquality.internal.api.ApiBridge;
|
||||
import org.openhab.binding.airquality.internal.api.Appreciation;
|
||||
import org.openhab.binding.airquality.internal.api.Index;
|
||||
import org.openhab.binding.airquality.internal.api.Pollutant;
|
||||
import org.openhab.binding.airquality.internal.api.Pollutant.SensitiveGroup;
|
||||
import org.openhab.binding.airquality.internal.api.dto.AirQualityData;
|
||||
import org.openhab.binding.airquality.internal.config.AirQualityConfiguration;
|
||||
import org.openhab.binding.airquality.internal.config.SensitiveGroupConfiguration;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.i18n.LocationProvider;
|
||||
import org.openhab.core.i18n.TimeZoneProvider;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PointType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.types.RawType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.thing.binding.BridgeHandler;
|
||||
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link AirQualityStationHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Kuba Wolanin - Initial contribution
|
||||
* @author Łukasz Dywicki - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AirQualityStationHandler extends BaseThingHandler {
|
||||
private final @NonNullByDefault({}) ClassLoader classLoader = AirQualityStationHandler.class.getClassLoader();
|
||||
private final Logger logger = LoggerFactory.getLogger(AirQualityStationHandler.class);
|
||||
private final TimeZoneProvider timeZoneProvider;
|
||||
private final LocationProvider locationProvider;
|
||||
|
||||
private @Nullable ScheduledFuture<?> refreshJob;
|
||||
|
||||
public AirQualityStationHandler(Thing thing, TimeZoneProvider timeZoneProvider, LocationProvider locationProvider) {
|
||||
super(thing);
|
||||
this.timeZoneProvider = timeZoneProvider;
|
||||
this.locationProvider = locationProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
logger.debug("Initializing Air Quality handler.");
|
||||
|
||||
if (thing.getProperties().isEmpty()) {
|
||||
discoverAttributes();
|
||||
}
|
||||
|
||||
AirQualityConfiguration config = getConfigAs(AirQualityConfiguration.class);
|
||||
try {
|
||||
config.checkValid();
|
||||
freeRefreshJob();
|
||||
refreshJob = scheduler.scheduleWithFixedDelay(this::updateAndPublishData, 0, config.refresh,
|
||||
TimeUnit.MINUTES);
|
||||
} catch (AirQualityException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void discoverAttributes() {
|
||||
getAirQualityData().ifPresent(data -> {
|
||||
// Update thing properties
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
properties.put(ATTRIBUTIONS, data.getAttributions());
|
||||
PointType serverLocation = locationProvider.getLocation();
|
||||
if (serverLocation != null) {
|
||||
PointType stationLocation = new PointType(data.getCity().getGeo());
|
||||
double distance = serverLocation.distanceFrom(stationLocation).doubleValue();
|
||||
properties.put(DISTANCE, new QuantityType<>(distance / 1000, KILO(SIUnits.METRE)).toString());
|
||||
}
|
||||
|
||||
// Search and remove missing pollutant channels
|
||||
List<Channel> channels = new ArrayList<>(getThing().getChannels());
|
||||
Stream.of(Pollutant.values()).forEach(pollutant -> {
|
||||
String groupName = pollutant.name().toLowerCase();
|
||||
double value = data.getIaqiValue(pollutant);
|
||||
channels.removeIf(channel -> value == -1 && groupName.equals(channel.getUID().getGroupId()));
|
||||
});
|
||||
|
||||
// Update thing configuration
|
||||
Configuration config = editConfiguration();
|
||||
config.put(AirQualityConfiguration.STATION_ID, data.getStationId());
|
||||
|
||||
ThingBuilder thingBuilder = editThing();
|
||||
thingBuilder.withChannels(channels).withConfiguration(config).withProperties(properties)
|
||||
.withLocation(data.getCity().getName());
|
||||
updateThing(thingBuilder.build());
|
||||
});
|
||||
}
|
||||
|
||||
private void updateAndPublishData() {
|
||||
getAirQualityData().ifPresent(data -> {
|
||||
getThing().getChannels().stream().filter(channel -> isLinked(channel.getUID().getId())).forEach(channel -> {
|
||||
State state;
|
||||
ChannelUID channelUID = channel.getUID();
|
||||
ChannelTypeUID channelTypeUID = channel.getChannelTypeUID();
|
||||
if (channelTypeUID != null && SENSITIVE.equals(channelTypeUID.getId().toString())) {
|
||||
SensitiveGroupConfiguration configuration = channel.getConfiguration()
|
||||
.as(SensitiveGroupConfiguration.class);
|
||||
state = getSensitive(configuration.asSensitiveGroup(), data);
|
||||
} else {
|
||||
state = getValue(channelUID.getIdWithoutGroup(), channelUID.getGroupId(), data);
|
||||
}
|
||||
updateState(channelUID, state);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
logger.debug("Disposing the Air Quality handler.");
|
||||
freeRefreshJob();
|
||||
}
|
||||
|
||||
private void freeRefreshJob() {
|
||||
ScheduledFuture<?> job = this.refreshJob;
|
||||
if (job != null && !job.isCancelled()) {
|
||||
job.cancel(true);
|
||||
refreshJob = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (command instanceof RefreshType) {
|
||||
updateAndPublishData();
|
||||
return;
|
||||
}
|
||||
logger.debug("The Air Quality binding is read-only and can not handle command {}", command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request new air quality data to the aqicn.org service
|
||||
*
|
||||
* @return an optional air quality data object mapping the JSON response
|
||||
*/
|
||||
private Optional<AirQualityData> getAirQualityData() {
|
||||
AirQualityData result = null;
|
||||
ApiBridge apiBridge = getApiBridge();
|
||||
if (apiBridge != null) {
|
||||
AirQualityConfiguration config = getConfigAs(AirQualityConfiguration.class);
|
||||
try {
|
||||
result = apiBridge.getData(config.stationId, config.location, 0);
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} catch (AirQualityException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
return Optional.ofNullable(result);
|
||||
}
|
||||
|
||||
private @Nullable ApiBridge getApiBridge() {
|
||||
Bridge bridge = this.getBridge();
|
||||
if (bridge != null && bridge.getStatus() == ThingStatus.ONLINE) {
|
||||
BridgeHandler handler = bridge.getHandler();
|
||||
if (handler instanceof AirQualityBridgeHandler) {
|
||||
return ((AirQualityBridgeHandler) handler).getApiBridge();
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/incorrect-bridge");
|
||||
}
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private State indexedValue(String channelId, double idx, @Nullable Pollutant pollutant) {
|
||||
Index index = Index.find(idx);
|
||||
if (index != null) {
|
||||
switch (channelId) {
|
||||
case INDEX:
|
||||
return new DecimalType(idx);
|
||||
case VALUE:
|
||||
return pollutant != null ? pollutant.toQuantity(idx) : UnDefType.UNDEF;
|
||||
case ICON:
|
||||
byte[] bytes = getResource(String.format("picto/%s.svg", index.getCategory().name().toLowerCase()));
|
||||
return bytes != null ? new RawType(bytes, "image/svg+xml") : UnDefType.UNDEF;
|
||||
case COLOR:
|
||||
return index.getCategory().getColor();
|
||||
case ALERT_LEVEL:
|
||||
return new DecimalType(index.getCategory().ordinal());
|
||||
}
|
||||
}
|
||||
return UnDefType.UNDEF;
|
||||
}
|
||||
|
||||
private State getSensitive(@Nullable SensitiveGroup sensitiveGroup, AirQualityData data) {
|
||||
if (sensitiveGroup != null) {
|
||||
int threshHold = Appreciation.UNHEALTHY_FSG.ordinal();
|
||||
for (Pollutant pollutant : Pollutant.values()) {
|
||||
Index index = Index.find(data.getIaqiValue(pollutant));
|
||||
if (index != null && pollutant.sensitiveGroups.contains(sensitiveGroup)
|
||||
&& index.getCategory().ordinal() >= threshHold) {
|
||||
return OnOffType.ON;
|
||||
}
|
||||
}
|
||||
return OnOffType.OFF;
|
||||
}
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
|
||||
private State getValue(String channelId, @Nullable String groupId, AirQualityData data) {
|
||||
switch (channelId) {
|
||||
case TEMPERATURE:
|
||||
double temp = data.getIaqiValue("t");
|
||||
return temp != -1 ? new QuantityType<>(temp, SIUnits.CELSIUS) : UnDefType.UNDEF;
|
||||
case PRESSURE:
|
||||
double press = data.getIaqiValue("p");
|
||||
return press != -1 ? new QuantityType<>(press, HECTO(SIUnits.PASCAL)) : UnDefType.UNDEF;
|
||||
case HUMIDITY:
|
||||
double hum = data.getIaqiValue("h");
|
||||
return hum != -1 ? new QuantityType<>(hum, Units.PERCENT) : UnDefType.UNDEF;
|
||||
case TIMESTAMP:
|
||||
return new DateTimeType(
|
||||
data.getTime().getObservationTime().withZoneSameLocal(timeZoneProvider.getTimeZone()));
|
||||
case DOMINENT:
|
||||
return new StringType(data.getDominentPol());
|
||||
case DEW_POINT:
|
||||
double dp = data.getIaqiValue("dew");
|
||||
return dp != -1 ? new QuantityType<>(dp, SIUnits.CELSIUS) : UnDefType.UNDEF;
|
||||
case WIND_SPEED:
|
||||
double w = data.getIaqiValue("w");
|
||||
return w != -1 ? new QuantityType<>(w, Units.METRE_PER_SECOND) : UnDefType.UNDEF;
|
||||
default:
|
||||
if (groupId != null) {
|
||||
double idx = -1;
|
||||
Pollutant pollutant = null;
|
||||
if (AQI.equals(groupId)) {
|
||||
idx = data.getAqi();
|
||||
} else {
|
||||
pollutant = Pollutant.valueOf(groupId.toUpperCase());
|
||||
idx = data.getIaqiValue(pollutant);
|
||||
}
|
||||
return indexedValue(channelId, idx, pollutant);
|
||||
}
|
||||
return UnDefType.UNDEF;
|
||||
}
|
||||
}
|
||||
|
||||
private byte @Nullable [] getResource(String iconPath) {
|
||||
try (InputStream stream = classLoader.getResourceAsStream(iconPath)) {
|
||||
return stream != null ? stream.readAllBytes() : null;
|
||||
} catch (IOException e) {
|
||||
logger.warn("Unable to load ressource '{}' : {}", iconPath, e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -4,6 +4,5 @@
|
|||
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
|
||||
|
||||
<name>Air Quality Binding</name>
|
||||
<description>Measure Air Quality Index and details about pollution particles for a given location</description>
|
||||
|
||||
</binding:binding>
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
# binding
|
||||
binding.airquality.name = Air Quality Binding
|
||||
binding.airquality.description = Measure Air Quality Index and details about pollution particles for a given location.
|
||||
|
||||
# thing types
|
||||
thing-type.airquality.api.label = Air Quality API
|
||||
thing-type.airquality.api.description = Bridge to the Air Quality API service.
|
||||
thing-type.airquality.station.label = Air Quality Station
|
||||
thing-type.airquality.station.description = Provides various air quality data from the World Air Quality Project. In order to receive the data, you must register an account on http://aqicn.org/data-platform/token/ and get your API token.
|
||||
|
||||
# thing types config
|
||||
thing-type.config.airquality.api.apiKey.label = API Key
|
||||
thing-type.config.airquality.api.apiKey.description = Data-platform token to access the AQIcn.org service.
|
||||
thing-type.config.airquality.station.location.label = Location
|
||||
thing-type.config.airquality.station.location.description = Your geo coordinates separated with comma (e.g. "37.8,-122.4").
|
||||
thing-type.config.airquality.station.stationId.label = Station ID
|
||||
thing-type.config.airquality.station.stationId.description = Fill in case you want to receive data from the specific station.
|
||||
thing-type.config.airquality.station.refresh.label = Refresh Interval
|
||||
thing-type.config.airquality.station.refresh.description = Specifies the refresh interval in minutes.
|
||||
|
||||
# Channel groups labels
|
||||
pm25ChannelGroupLabel = PM 2.5 - Particles less than 2.5 µm in diameter.
|
||||
pm10ChannelGroupLabel = PM 10 - Coarse Dust Particles.
|
||||
no2ChannelGroupLabel = NO2 - Nitrogen Dioxide.
|
||||
so2ChannelGroupLabel = SO2 - Sulfur Dioxide.
|
||||
coChannelGroupLabel = CO - Carbon Monoxide.
|
||||
o3ChannelGroupLabel = O3 - Ozone.
|
||||
aqiChannelGroupLabel = AQI - Synthetic Air Quality Index.
|
||||
weatherChannelGroupLabel = Weather Data
|
||||
|
||||
# Channel types labels
|
||||
timestampChannelLabel = Observation Time
|
||||
timestampChannelDescription = Observation date and time.
|
||||
dominentChannelLabel = Dominent Pollutant
|
||||
dewPointLabel = Dew-Point Temperature
|
||||
dewPointDescription = Forecasted dew-point temperature.
|
||||
windSpeedLabel = Wind Speed
|
||||
pictoChannelLabel = Pictogram
|
||||
pictoChannelDescription = Pictogram associated to alert level.
|
||||
colorChannelLabel = AQI Color
|
||||
colorChannelDescription = Color associated to given AQI Index.
|
||||
|
||||
# Channel options values
|
||||
alertLevelChannelLabel = Alert Level
|
||||
alertLevelChannelDescription = Alert level associated to Air Quality Index scale.
|
||||
alertLevelOption0 = Good
|
||||
alertLevelOption1 = Moderate
|
||||
alertLevelOption2 = Unhealthy for Sensitive Groups
|
||||
alertLevelOption3 = Unhealthy
|
||||
alertLevelOption4 = Very Unhealthy
|
||||
alertLevelOption5 = Hazardous
|
||||
|
||||
pollutantPm25 = Fine particles
|
||||
pollutantPm10 = Coarse dust particles
|
||||
pollutantO3 = Ozone
|
||||
pollutantNO2 = Nitrogen Dioxide
|
||||
pollutantCO = Carbon Monoxide
|
||||
pollutantSO2 = Sulfur Dioxide
|
||||
|
||||
# Error messages
|
||||
null-or-empty-api-key = Null or empty API key
|
||||
incorrect-bridge = Wrong bridge type
|
|
@ -1,30 +1,62 @@
|
|||
# binding
|
||||
binding.airquality.name = Extension Air Quality
|
||||
binding.airquality.description = Indice de qualité de l'air et informations sur la pollution aux particules pour un emplacement donné.
|
||||
binding.airquality.description = Indice de qualité de l'air et informations sur la pollution aux particules pour un emplacement donné.
|
||||
|
||||
# thing types
|
||||
thing-type.airquality.aqi.label = Qualité de l'air
|
||||
thing-type.airquality.aqi.description = Fournit diverses données sur la qualité de l'air du World Air Quality Project. Pour recevoir les données, vous devez créer un compte sur http://aqicn.org/data-platform/token/ pour obtenir votre token API.
|
||||
thing-type.airquality.api.label = API Air Quality
|
||||
thing-type.airquality.api.description = Passerelle vers le service de données Air Quality.
|
||||
thing-type.airquality.station.label = Qualité de l'air
|
||||
thing-type.airquality.station.description = Fournit diverses données sur la qualité de l'air du World Air Quality Project. Pour recevoir les données, vous devez créer un compte sur http://aqicn.org/data-platform/token/ pour obtenir votre token API.
|
||||
|
||||
channel-type.airquality.aqiLevel.label = Indice
|
||||
channel-type.airquality.aqiDescription.label = Appréciation
|
||||
channel-type.airquality.observationTime.label = Heure d'observation
|
||||
channel-type.airquality.temperature.label = Température
|
||||
channel-type.airquality.pressure.label = Pression
|
||||
channel-type.airquality.humidity.label = Humidité
|
||||
channel-type.airquality.dominentpol.label = Polluant principal
|
||||
# thing types config
|
||||
thing-type.config.airquality.api.apiKey.label = Clé API
|
||||
thing-type.config.airquality.api.apiKey.description = Jeton d'accès aux données du service AQIcn.org.
|
||||
thing-type.config.airquality.station.location.label = Localisation
|
||||
thing-type.config.airquality.station.location.description = Coordonnées géographiques (séparées par une virgule : "37.8,-122.4").
|
||||
thing-type.config.airquality.station.stationId.label = ID Station
|
||||
thing-type.config.airquality.station.stationId.description = Renseignez cette valeur si vous souhaitez les données d'une station spécifique.
|
||||
thing-type.config.airquality.station.refresh.label = Période de mise à jour
|
||||
thing-type.config.airquality.station.refresh.description = Définisser l'intervalle de mise à jour en minutes.
|
||||
|
||||
# Channel groups labels
|
||||
pm25ChannelGroupLabel = PM 2.5 - Particules de diametre inférieur à 2.5 µm.
|
||||
pm10ChannelGroupLabel = PM 10 - Particules fines de poussière.
|
||||
no2ChannelGroupLabel = NO2 - Dioxyde d'azote.
|
||||
so2ChannelGroupLabel = SO2 - Dioxyde de soufre.
|
||||
coChannelGroupLabel = CO - Monoxyde de carbone.
|
||||
o3ChannelGroupLabel = O3 - Ozone.
|
||||
aqiChannelGroupLabel = AQI - Indice Global de Qualité de l'Air.
|
||||
weatherChannelGroupLabel = Données Méteo.
|
||||
|
||||
channel-type.airquality.aqiDescription.state.option.GOOD = Bonne
|
||||
channel-type.airquality.aqiDescription.state.option.MODERATE = Modérée
|
||||
channel-type.airquality.aqiDescription.state.option.UNHEALTHY_FOR_SENSITIVE = Mauvaise pour les groupes sensibles
|
||||
channel-type.airquality.aqiDescription.state.option.UNHEALTHY = Mauvaise
|
||||
channel-type.airquality.aqiDescription.state.option.VERY_UNHEALTHY = Très mauvaise
|
||||
channel-type.airquality.aqiDescription.state.option.HAZARDOUS = Dangereuse
|
||||
# Channel types labels
|
||||
timestampChannelLabel = Horodatage
|
||||
timestampChannelDescription = Date et heure des oObservations.
|
||||
dominentChannelLabel = Polluant Principal
|
||||
dewPointLabel = Température de Rosée
|
||||
dewPointDescription = Température du point de Rosée.
|
||||
windSpeedLabel = Vitesse du Vent
|
||||
pictoChannelLabel = Pictogramme
|
||||
pictoChannelDescription = Pictogramme associé au niveau d'alerte.
|
||||
colorChannelLabel = Couleur AQI
|
||||
colorChannelDescription = Couleur associée à l'Indice de Qualité d'Air.
|
||||
|
||||
channel-type.airquality.dominentPol.state.option.pm25 = Particules fines
|
||||
channel-type.airquality.dominentPol.state.option.pm10 = Particules de poussière
|
||||
channel-type.airquality.dominentPol.state.option.o3 = Ozone
|
||||
channel-type.airquality.dominentPol.state.option.no2 = Dioxyde d'azote
|
||||
channel-type.airquality.dominentPol.state.option.co = Monoxyde de carbone
|
||||
channel-type.airquality.dominentPol.state.option.so2 = Dioxyde de soufre
|
||||
# Channel options values
|
||||
alertLevelChannelLabel = Niveau d'Alerte
|
||||
alertLevelChannelDescription = Niveau d'alerte associé à l'Indice de Qualité d'Air.
|
||||
alertLevelOption0 = Bonne
|
||||
alertLevelOption1 = Modérée
|
||||
alertLevelOption2 = Mauvaise pour les groupes sensibles
|
||||
alertLevelOption3 = Mauvaise
|
||||
alertLevelOption4 = Très mauvaise
|
||||
alertLevelOption5 = Dangereuse
|
||||
|
||||
pollutantPm25 = Particules de diametre inférieur à 2.5 µm.
|
||||
pollutantPm10 = Particules fines de poussière.
|
||||
pollutantO3 = Ozone
|
||||
pollutantNO2 = Dioxyde d'azote.
|
||||
pollutantCO = Monoxyde de carbone.
|
||||
pollutantSO2 = Dioxyde de soufre.
|
||||
|
||||
# Error messages
|
||||
null-or-empty-api-key = Clef API nulle ou vide
|
||||
incorrect-bridge = Le type de bridge est incorrect
|
||||
|
|
|
@ -4,55 +4,58 @@
|
|||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- Air Quality Thing -->
|
||||
<thing-type id="aqi">
|
||||
<label>Air Quality</label>
|
||||
<description>
|
||||
Provides various air quality data from the World Air Quality Project.
|
||||
In order to receive the data, you
|
||||
must register an account on http://aqicn.org/data-platform/token/ and get your API
|
||||
token.
|
||||
</description>
|
||||
|
||||
<channels>
|
||||
<channel id="aqiLevel" typeId="aqiLevel"/>
|
||||
<channel id="aqiColor" typeId="aqiColor"/>
|
||||
<channel id="aqiDescription" typeId="aqiDescription"/>
|
||||
<channel id="pm25" typeId="pm25"/>
|
||||
<channel id="pm10" typeId="pm10"/>
|
||||
<channel id="o3" typeId="o3"/>
|
||||
<channel id="no2" typeId="no2"/>
|
||||
<channel id="co" typeId="co"/>
|
||||
<channel id="so2" typeId="so2"/>
|
||||
<channel id="locationName" typeId="locationName"/>
|
||||
<channel id="stationLocation" typeId="stationLocation"/>
|
||||
<channel id="stationId" typeId="stationId"/>
|
||||
<channel id="observationTime" typeId="observationTime"/>
|
||||
<channel id="temperature" typeId="temperature"/>
|
||||
<channel id="pressure" typeId="pressure"/>
|
||||
<channel id="humidity" typeId="humidity"/>
|
||||
<channel id="dominentpol" typeId="dominentPol"/>
|
||||
</channels>
|
||||
<bridge-type id="api">
|
||||
<label>Air Quality API</label>
|
||||
|
||||
<config-description>
|
||||
<parameter name="apikey" type="text" required="true">
|
||||
<parameter name="apiKey" type="text" required="true">
|
||||
<context>password</context>
|
||||
<label>API Key</label>
|
||||
<description>Data-platform token to access the AQIcn.org service</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</bridge-type>
|
||||
|
||||
<!-- Air Quality Thing -->
|
||||
<thing-type id="station" extensible="sensitive-group">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="api"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Air Quality Station</label>
|
||||
|
||||
<channel-groups>
|
||||
<channel-group id="aqi" typeId="aqi"/>
|
||||
<channel-group id="weather" typeId="weather"/>
|
||||
<channel-group id="pm25" typeId="pollutant-density">
|
||||
<label>@text/pm25ChannelGroupLabel</label>
|
||||
</channel-group>
|
||||
<channel-group id="pm10" typeId="pollutant-density">
|
||||
<label>@text/pm10ChannelGroupLabel</label>
|
||||
</channel-group>
|
||||
<channel-group id="no2" typeId="pollutant-ppb">
|
||||
<label>@text/no2ChannelGroupLabel</label>
|
||||
</channel-group>
|
||||
<channel-group id="so2" typeId="pollutant-ppb">
|
||||
<label>@text/so2ChannelGroupLabel</label>
|
||||
</channel-group>
|
||||
<channel-group id="co" typeId="pollutant-ppb">
|
||||
<label>@text/coChannelGroupLabel</label>
|
||||
</channel-group>
|
||||
<channel-group id="o3" typeId="pollutant-ppb">
|
||||
<label>@text/o3ChannelGroupLabel</label>
|
||||
</channel-group>
|
||||
</channel-groups>
|
||||
|
||||
<config-description>
|
||||
<parameter name="location" type="text" required="false"
|
||||
pattern="^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?)[,]\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$">
|
||||
<label>Location</label>
|
||||
<description>Your geo coordinates separated with comma (e.g. "37.8,-122.4").</description>
|
||||
</parameter>
|
||||
<parameter name="stationId" type="integer" required="false">
|
||||
<label>Station ID</label>
|
||||
<description>Fill only in case you want to receive data from the specific station</description>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="refresh" type="integer" min="30" required="false" unit="min">
|
||||
<label>Refresh Interval</label>
|
||||
<description>Specifies the refresh interval in minutes.</description>
|
||||
<advanced>true</advanced>
|
||||
<default>60</default>
|
||||
<unitLabel>Minutes</unitLabel>
|
||||
|
@ -60,155 +63,172 @@
|
|||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<channel-type id="aqiLevel">
|
||||
<channel-group-type id="aqi">
|
||||
<label>@text/aqiChannelGroupLabel</label>
|
||||
<channels>
|
||||
<channel id="alert-level" typeId="alert-level"/>
|
||||
<channel id="index" typeId="index"/>
|
||||
<channel id="timestamp" typeId="timestamp"/>
|
||||
<channel id="dominent" typeId="dominent"/>
|
||||
<channel id="icon" typeId="alert-icon"/>
|
||||
<channel id="color" typeId="alert-color"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="weather">
|
||||
<label>@text/weatherChannelGroupLabel</label>
|
||||
<channels>
|
||||
<channel id="temperature" typeId="system.outdoor-temperature"/>
|
||||
<channel id="pressure" typeId="system.barometric-pressure"/>
|
||||
<channel id="humidity" typeId="system.atmospheric-humidity"/>
|
||||
<channel id="dew-point" typeId="dew-point"/>
|
||||
<channel id="wind-speed" typeId="system.wind-speed"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="pollutant-density">
|
||||
<label>Pollutant</label>
|
||||
<channels>
|
||||
<channel id="value" typeId="density-value"/>
|
||||
<channel id="index" typeId="index-adv"/>
|
||||
<channel id="alert-level" typeId="alert-level"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="pollutant-ppb">
|
||||
<label>Pollutant</label>
|
||||
<channels>
|
||||
<channel id="value" typeId="ppb-value"/>
|
||||
<channel id="index" typeId="index-adv"/>
|
||||
<channel id="alert-level" typeId="alert-level"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-type id="index">
|
||||
<item-type>Number</item-type>
|
||||
<label>Air Quality Index</label>
|
||||
<description></description>
|
||||
<category>Air Quality Index</category>
|
||||
<label>Index</label>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%d" min="0" max="500"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="aqiDescription">
|
||||
<item-type>String</item-type>
|
||||
<label>AQI Description</label>
|
||||
<description></description>
|
||||
<category>AQI Description</category>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="GOOD">Good</option>
|
||||
<option value="MODERATE">Moderate</option>
|
||||
<option value="UNHEALTHY_FOR_SENSITIVE">Unhealthy for Sensitive Groups</option>
|
||||
<option value="UNHEALTHY">Unhealthy</option>
|
||||
<option value="VERY_UNHEALTHY">Very Unhealthy</option>
|
||||
<option value="HAZARDOUS">Hazardous</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="pm25">
|
||||
<channel-type id="index-adv" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>PM2.5</label>
|
||||
<description>Fine particles pollution level</description>
|
||||
<category>PM2.5</category>
|
||||
<label>Index</label>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%d" min="0" max="500"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="pm10">
|
||||
<item-type>Number</item-type>
|
||||
<label>PM10</label>
|
||||
<description>Coarse dust particles pollution level</description>
|
||||
<category>PM10</category>
|
||||
<state readOnly="true" pattern="%d" min="0" max="500"/>
|
||||
<channel-type id="density-value">
|
||||
<item-type>Number:Density</item-type>
|
||||
<label>Measure</label>
|
||||
<state readOnly="true" pattern="%.2f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="o3">
|
||||
<item-type>Number</item-type>
|
||||
<label>O3</label>
|
||||
<description>Ozone level</description>
|
||||
<category>O3</category>
|
||||
<state readOnly="true" pattern="%.1f" min="0" max="500"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="no2">
|
||||
<item-type>Number</item-type>
|
||||
<label>NO2</label>
|
||||
<description>Nitrogen dioxide level</description>
|
||||
<category>NO2</category>
|
||||
<state readOnly="true" pattern="%.1f" min="0" max="500"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="co">
|
||||
<item-type>Number</item-type>
|
||||
<label>CO</label>
|
||||
<description>Carbon monoxide level</description>
|
||||
<category>CO</category>
|
||||
<state readOnly="true" pattern="%.1f" min="0" max="500"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="so2">
|
||||
<item-type>Number</item-type>
|
||||
<label>SO2</label>
|
||||
<description>Sulfur dioxide level</description>
|
||||
<category>SO2</category>
|
||||
<state readOnly="true" pattern="%.1f"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="locationName" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<label>Location</label>
|
||||
<description>Nearest measuring station location</description>
|
||||
<category>Location</category>
|
||||
<state readOnly="true" pattern="%s"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="stationLocation" advanced="true">
|
||||
<item-type>Location</item-type>
|
||||
<label>Station Location</label>
|
||||
<description>Location of the measuring station</description>
|
||||
<category>Station Location</category>
|
||||
<state readOnly="true" pattern="%2$s°N,%3$s°W"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="stationId" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Station ID</label>
|
||||
<description>Unique measuring station ID</description>
|
||||
<category>Station ID</category>
|
||||
<state readOnly="true" pattern="%d"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="observationTime" advanced="true">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Observation Time</label>
|
||||
<description>Observation date and time</description>
|
||||
<category>Observation time</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="temperature" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Temperature</label>
|
||||
<description>Temperature</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="pressure" advanced="true">
|
||||
<item-type>Number:Pressure</item-type>
|
||||
<label>Pressure</label>
|
||||
<description>Current Pressure</description>
|
||||
<category>Pressure</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="humidity" advanced="true">
|
||||
<channel-type id="ppb-value">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Humidity</label>
|
||||
<description>Current humidity</description>
|
||||
<category>Humidity</category>
|
||||
<state readOnly="true" min="0" max="100" pattern="%.2f %unit%"/>
|
||||
<label>Measure</label>
|
||||
<state readOnly="true" pattern="%.2f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="dominentPol">
|
||||
<item-type>String</item-type>
|
||||
<label>Dominent Polutor</label>
|
||||
<channel-type id="alert-level">
|
||||
<item-type>Number</item-type>
|
||||
<label>@text/alertLevelChannelLabel</label>
|
||||
<description>@text/alertLevelChannelDescription</description>
|
||||
<category>error</category>
|
||||
<tags>
|
||||
<tag>Alarm</tag>
|
||||
</tags>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="pm25">Fine particles</option>
|
||||
<option value="pm10">Coarse dust particles</option>
|
||||
<option value="o3">Ozone</option>
|
||||
<option value="no2">Nitrogen Dioxide</option>
|
||||
<option value="co">Carbon Monoxide</option>
|
||||
<option value="so2">Sulfur Dioxide</option>
|
||||
<option value="0">@text/alertLevelOption0</option>
|
||||
<option value="1">@text/alertLevelOption1</option>
|
||||
<option value="2">@text/alertLevelOption2</option>
|
||||
<option value="3">@text/alertLevelOption3</option>
|
||||
<option value="4">@text/alertLevelOption4</option>
|
||||
<option value="5">@text/alertLevelOption5</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="aqiColor" advanced="true">
|
||||
<item-type>Color</item-type>
|
||||
<label>AQI Color</label>
|
||||
<description>Color associated to given AQI Index.</description>
|
||||
<channel-type id="timestamp" advanced="true">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>@text/timestampChannelLabel</label>
|
||||
<description>@text/timestampChannelDescription</description>
|
||||
<category>time</category>
|
||||
<tags>
|
||||
<tag>Status</tag>
|
||||
<tag>Timestamp</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="dominent">
|
||||
<item-type>String</item-type>
|
||||
<label>@text/dominentChannelLabel</label>
|
||||
<tags>
|
||||
<tag>Status</tag>
|
||||
</tags>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="pm25">@text/pollutantPm25</option>
|
||||
<option value="pm10">@text/pollutantPm10</option>
|
||||
<option value="o3">@text/pollutantO3</option>
|
||||
<option value="no2">@text/pollutantNO2</option>
|
||||
<option value="co">@text/pollutantCO</option>
|
||||
<option value="so2">@text/pollutantSO2</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="dew-point" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>@text/dewPointLabel</label>
|
||||
<description>@text/dewPointDescription</description>
|
||||
<category>Temperature</category>
|
||||
<tags>
|
||||
<tag>Point</tag>
|
||||
<tag>Temperature</tag>
|
||||
</tags>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="alert-color" advanced="true">
|
||||
<item-type>Color</item-type>
|
||||
<label>@text/colorChannelLabel</label>
|
||||
<description>@text/colorChannelDescription</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="alert-icon">
|
||||
<item-type>Image</item-type>
|
||||
<label>@text/pictoChannelLabel</label>
|
||||
<description>@text/pictoChannelDescription</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="sensitive-group">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Sensitive Group</label>
|
||||
<description>Checked if sensitive group is exposed to pollutant.</description>
|
||||
<state readOnly="true"/>
|
||||
<config-description>
|
||||
<parameter name="group" type="text">
|
||||
<label>Group</label>
|
||||
<description>Defines the kind of sensitivity</description>
|
||||
<options>
|
||||
<option value="RESPIRATORY">People with respiratory disease.</option>
|
||||
<option value="HEART">People with heart disease.</option>
|
||||
<option value="ELDERLY">The elderly.</option>
|
||||
<option value="CHILDREN">Children.</option>
|
||||
<option value="ASTHMA">People with asthma.</option>
|
||||
</options>
|
||||
<default>RESPIRATORY</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="good-air-quality" width="1024pt" height="1024pt" viewBox="0 0 650 650" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="#00e400" stroke="#00e400" stroke-width="2" opacity="1.00" d="M 306.143 12.125 C 349.223 9.135 392.903 15.025 433.623 29.385 C 471.263 42.665 506.383 63.115 536.423 89.395 C 593.563 138.785 632.063 209.375 641.783 284.345 C 650.263 346.445 639.623 411.065 611.263 466.985 C 588.543 512.235 554.663 551.805 513.573 581.365 C 465.893 615.905 408.383 636.675 349.623 640.475 C 307.233 643.405 264.223 637.835 224.063 623.905 C 153.253 599.745 91.793 549.415 54.083 484.805 C 33.383 449.715 19.703 410.505 14.083 370.155 C 7.803 325.485 11.193 279.455 24.183 236.255 C 35.883 197.155 55.413 160.445 81.143 128.775 C 109.873 93.325 146.343 64.175 187.283 44.015 C 224.303 25.725 264.943 14.805 306.143 12.125 M 256.393 98.485 C 231.103 104.515 208.583 119.915 192.323 140.045 C 175.843 160.115 165.253 184.365 158.433 209.235 C 157.343 213.885 155.703 218.405 155.603 223.245 C 153.403 236.825 155.313 250.535 156.203 264.135 C 157.733 278.795 160.913 293.215 163.223 307.765 C 164.383 318.965 166.643 330.075 168.173 341.255 C 164.183 344.785 159.333 347.335 155.763 351.325 C 152.073 355.435 153.433 361.265 153.563 366.265 C 155.443 382.635 161.873 397.965 167.473 413.325 C 169.643 419.515 173.303 425.215 178.413 429.365 C 184.623 435.015 192.703 437.605 200.493 440.235 C 217.353 475.275 238.823 508.805 268.133 534.745 C 275.113 540.525 281.793 546.995 290.313 550.495 C 305.483 556.815 322.313 557.785 338.553 556.995 C 353.393 556.165 368.733 552.605 380.683 543.335 C 415.123 516.455 439.753 479.195 458.553 440.215 C 468.003 437.385 477.563 433.455 484.183 425.835 C 490.383 419.355 492.363 410.345 495.623 402.265 C 500.903 387.505 506.543 372.205 505.603 356.265 C 503.893 348.845 495.933 345.985 490.873 341.205 C 494.603 317.035 499.053 292.765 498.213 268.205 C 498.253 254.515 496.033 240.965 493.023 227.655 L 492.483 227.165 C 489.283 211.515 485.763 195.795 479.993 180.855 C 475.643 170.025 470.963 158.665 462.073 150.695 C 455.643 140.715 446.953 132.375 437.523 125.245 C 420.383 112.515 400.393 104.085 379.743 99.055 C 339.363 89.145 297.033 91.595 256.393 98.485 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="5" opacity="1.00" d="M 254.845 96.98 C 266.968 94.65 279.335 94.2 291.608 93.16 C 322.469 91.88 354.045 95.17 383.031 106.58 C 405.86 115.729 427.428 130.169 441.234 150.908 C 453.285 163.028 458.63 179.828 463.719 195.687 C 466.63 206.457 471.188 216.887 472.511 228.016 C 473.977 232.846 474.595 237.936 474.533 242.996 C 474.696 243.456 475.023 244.356 475.197 244.806 C 476.208 269.045 476.572 293.654 471.189 317.404 C 468.175 326.273 466.835 335.603 464.833 344.743 C 460.622 365.972 456.31 387.192 452.68 408.531 C 452.07 407.251 451.481 405.971 450.901 404.691 C 448.31 385.812 445.779 366.932 443.427 348.023 C 442.7 328.333 436.621 308.474 424.334 292.794 C 411.3 276.215 392.509 264.185 372.13 259.045 C 381.141 272.525 395.187 281.325 407.127 291.914 C 399.591 292.534 392.215 290.394 385.225 287.765 C 371.064 282.335 357.699 275.015 344.671 267.285 C 326.058 256.225 308.225 243.916 290.621 231.316 C 293.759 237.746 298.559 243.156 303.378 248.376 C 319.725 265.295 338.513 279.585 357.1 293.914 C 348.068 294.924 339.092 292.864 330.404 290.544 C 311.843 285.035 294.388 276.435 277.28 267.475 C 251.736 253.666 227.08 238.226 203.236 221.646 C 201.42 239.626 197.102 257.225 192.812 274.725 C 187.463 289.565 184.99 305.264 183.547 320.934 C 181.442 349.603 182.828 378.472 186.451 407.011 C 187.144 412.801 187.628 418.621 187.771 424.461 C 187.766 425.091 187.755 426.341 187.75 426.971 C 187.585 426.341 187.246 425.071 187.071 424.441 C 185.812 419.201 184.273 414.031 182.815 408.841 C 176.914 387.432 170.785 366.082 164.395 344.823 C 162.971 340.193 161.556 335.563 159.982 330.983 C 153.161 312.194 149.454 292.484 146.646 272.785 C 145.307 266.175 145.257 259.415 144.547 252.736 C 143.191 238.586 143.332 224.056 147.129 210.307 C 153.308 185.987 163.051 162.248 178.281 142.209 C 196.531 118.049 224.032 99.38 254.845 96.98 Z" style="" transform="matrix(0.999972, 0.007475, -0.007475, 0.999972, 1.951674, -2.308377)"/>
|
||||
<path fill="#00e400" stroke="#00e400" stroke-width="5" opacity="1.00" d="M 202.369 221.696 C 226.213 238.275 250.869 253.715 276.413 267.525 C 293.521 276.484 310.975 285.084 329.537 290.594 C 338.225 292.914 347.2 294.974 356.233 293.964 C 337.646 279.634 318.858 265.345 302.511 248.425 C 297.692 243.205 292.892 237.795 289.753 231.366 C 307.358 243.965 325.191 256.275 343.804 267.335 C 356.832 275.064 370.197 282.384 384.358 287.814 C 391.348 290.444 398.724 292.584 406.26 291.964 C 394.32 281.374 380.274 272.574 371.263 259.095 C 391.642 264.235 410.432 276.264 423.467 292.844 C 435.754 308.523 441.833 328.383 442.56 348.072 C 444.911 366.982 447.443 385.861 450.034 404.741 C 450.188 406.691 450.283 408.641 450.408 410.611 C 445.991 408.381 441.604 406.101 437.177 403.901 C 425.426 429.18 413.024 454.369 396.642 476.999 C 385.122 493.058 371.492 507.738 355.589 519.538 C 331.276 533.877 299.004 533.817 274.565 519.288 C 258.727 507.548 245.018 493.088 233.389 477.209 C 216.63 454.549 203.781 429.34 191.641 404.021 C 189.609 405.011 187.596 406.021 185.584 407.061 C 181.96 378.521 180.575 349.652 182.68 320.983 C 184.123 305.314 186.596 289.614 191.945 274.774 C 196.234 257.275 200.553 239.675 202.369 221.696 M 340.816 313.193 C 359.611 311.043 378.64 310.903 397.468 313.143 C 382.446 298.274 355.749 298.764 340.816 313.193 M 229.923 313.143 C 248.867 310.983 268.047 310.923 286.996 313.373 C 271.796 298.644 245.004 298.444 229.923 313.143 M 356.804 330.203 C 353.026 333.113 353 339.023 356.185 342.432 C 365.461 348.502 379.584 347.552 386.265 338.183 C 385.629 334.763 383.984 331.423 380.979 329.493 C 373.794 324.723 363.656 325.093 356.804 330.203 M 241.361 334.293 C 242.559 339.383 246.154 343.952 251.384 345.242 C 260.832 347.692 270.963 343.732 277.794 337.203 C 272.524 330.503 264.129 325.883 255.485 326.753 C 249.939 327.193 245.021 330.263 241.361 334.293 M 293.685 396.081 C 306.648 401.811 321.798 401.711 334.768 396.311 C 322.049 389.811 306.43 390.021 293.685 396.081 M 267.056 439.21 C 271.91 455.789 283.02 471.769 299.668 478.079 C 312.181 482.469 326.814 481.439 338.01 474.229 C 350.321 466.329 358.343 453.099 362.269 439.2 C 330.579 436.67 298.718 436.62 267.056 439.21 Z" style="" transform="matrix(0.999972, 0.007475, -0.007475, 0.999972, 2.819187, -2.351964)"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="5" opacity="1.00" d="M 341.325 313.592 C 356.258 299.162 382.955 298.672 397.977 313.542 C 379.149 311.302 360.12 311.442 341.325 313.592 Z" style="" transform="matrix(0.999972, 0.007475, -0.007475, 0.999972, 2.313265, -2.754535)"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="5" opacity="1.00" d="M 230.434 312.715 C 245.515 298.015 272.307 298.215 287.507 312.945 C 268.559 310.495 249.379 310.555 230.434 312.715 Z" style="" transform="matrix(0.999972, 0.007475, -0.007475, 0.999972, 2.30482, -1.927218)"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="5" opacity="1.00" d="M 463.57 344.932 C 465.572 335.792 466.913 326.463 469.926 317.593 C 469.802 322.313 468.676 326.923 468.121 331.602 C 471.868 332.582 475.626 333.532 479.383 334.492 C 483.07 342.142 483.856 350.882 482.317 359.142 C 480.157 369.831 476.354 380.081 473.242 390.521 C 470.174 401.59 464.385 412.43 454.876 419.22 C 450.092 422.77 444.285 424.58 438.442 425.47 C 423.167 458.389 403.903 489.988 377.581 515.227 C 371.482 520.767 365.526 526.667 358.256 530.697 C 342.742 539.507 324.244 541.177 306.684 539.987 C 297.668 539.237 288.481 538.287 280.054 534.727 C 264.204 528.127 251.563 515.897 240.407 503.158 C 219.106 480.418 203.472 453.159 189.764 425.39 C 188.943 425.21 187.32 424.83 186.509 424.65 C 186.365 418.81 185.881 412.99 185.188 407.2 C 187.2 406.16 189.213 405.15 191.246 404.16 C 203.385 429.48 216.234 454.689 232.994 477.348 C 244.623 493.228 258.331 507.687 274.17 519.427 C 298.609 533.957 330.88 534.017 355.194 519.677 C 371.096 507.877 384.727 493.198 396.247 477.138 C 412.628 454.509 425.03 429.32 436.782 404.04 C 441.208 406.24 445.595 408.52 450.012 410.75 C 449.887 408.78 449.793 406.83 449.638 404.88 C 450.218 406.16 450.807 407.44 451.417 408.72 L 451.57 409.14 C 464.279 390.191 469.69 367.531 473.223 345.242 C 470.002 345.102 466.781 345.002 463.57 344.932 Z" style="" transform="matrix(0.999972, 0.007475, -0.007475, 0.999972, 3.215811, -2.485598)"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="5" opacity="1.00" d="M 357.1 330.608 C 363.952 325.498 374.089 325.128 381.275 329.898 C 384.28 331.828 385.925 335.168 386.56 338.588 C 379.88 347.957 365.757 348.907 356.481 342.838 C 353.296 339.428 353.321 333.518 357.1 330.608 Z" style="" transform="matrix(0.999972, 0.007475, -0.007475, 0.999972, 2.526449, -2.759088)"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="5" opacity="1.00" d="M 241.659 333.872 C 245.319 329.842 250.237 326.772 255.783 326.332 C 264.427 325.462 272.822 330.082 278.092 336.782 C 271.261 343.312 261.13 347.272 251.682 344.822 C 246.452 343.532 242.857 338.962 241.659 333.872 Z" style="" transform="matrix(0.999972, 0.007475, -0.007475, 0.999972, 2.518041, -1.933186)"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="5" opacity="1.00" d="M 159.106 329.907 C 160.68 334.487 162.094 339.116 163.519 343.746 C 160.378 343.586 157.227 343.456 154.086 343.356 C 158.04 366.566 164.305 390.085 178.022 409.665 C 179.317 409.025 180.633 408.395 181.938 407.765 C 183.397 412.954 184.936 418.124 186.195 423.364 C 173.793 420.494 163.242 411.064 158.773 399.175 C 155.007 389.015 151.58 378.745 148.074 368.506 C 144.119 357.186 143.083 344.396 148.02 333.267 C 151.692 332.087 155.639 331.667 159.106 329.907 Z" style="" transform="matrix(0.999972, 0.007475, -0.007475, 0.999972, 2.819973, -1.226198)"/>
|
||||
<path fill="#00e400" stroke="#00e400" stroke-width="5" opacity="1.00" d="M 154.087 343.376 C 157.228 343.476 160.379 343.606 163.52 343.766 C 169.909 365.026 176.039 386.375 181.939 407.784 C 180.634 408.414 179.318 409.044 178.023 409.684 C 164.306 390.105 158.04 366.586 154.087 343.376 Z" style="" transform="matrix(0.999972, 0.007475, -0.007475, 0.999972, 2.819256, -1.245378)"/>
|
||||
<path fill="#00e400" stroke="#00e400" stroke-width="5" opacity="1.00" d="M 463.955 345.889 C 467.166 345.959 470.386 346.059 473.608 346.199 C 470.074 368.488 464.663 391.148 451.955 410.097 L 451.802 409.677 C 455.432 388.338 459.744 367.118 463.955 345.889 Z" style="" transform="matrix(0.999972, 0.007475, -0.007475, 0.999972, 2.838425, -3.44816)"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="5" opacity="1.00" d="M 293.536 396.067 C 306.281 390.007 321.899 389.797 334.618 396.297 C 321.648 401.697 306.499 401.797 293.536 396.067 Z" style="" transform="matrix(0.999972, 0.007475, -0.007475, 0.999972, 2.968232, -2.336665)"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="5" opacity="1.00" d="M 266.436 439.198 C 298.097 436.609 329.959 436.659 361.648 439.188 C 357.722 453.088 349.701 466.318 337.39 474.217 C 326.193 481.427 311.56 482.457 299.047 478.067 C 282.4 471.758 271.29 455.778 266.436 439.198 M 278.081 446.488 C 282.901 455.898 289.759 464.908 299.523 469.538 C 306.178 472.827 313.826 472.448 321.002 471.938 C 334.657 469.848 344.351 458.288 350.023 446.488 C 326.038 445.968 302.057 445.978 278.081 446.488 Z" style="" transform="matrix(0.999972, 0.007475, -0.007475, 0.999972, 3.439647, -2.334642)"/>
|
||||
<path fill="#00e400" stroke="#00e400" stroke-width="5" opacity="1.00" d="M 278.079 446.488 C 302.056 445.978 326.037 445.968 350.021 446.488 C 344.349 458.288 334.655 469.847 321 471.937 C 313.824 472.447 306.177 472.827 299.522 469.537 C 289.757 464.907 282.9 455.898 278.079 446.488 Z" style="" transform="matrix(0.999972, 0.007475, -0.007475, 0.999972, 3.441201, -2.334695)"/>
|
||||
</svg>
|
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="hazardous-air-quality" width="1024pt" height="1024pt" viewBox="0 0 650 650" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="#7e0023" stroke="#7e0023" stroke-width="5" opacity="1.00" d="M 320.535 11.437 C 368.105 10.307 415.935 20.007 459.205 39.827 C 528.185 71.007 585.215 127.827 616.325 196.867 C 648.905 267.857 653.145 351.227 628.275 425.237 C 610.775 478.107 578.695 525.997 536.765 562.607 C 498.645 596.107 452.345 620.217 403.025 632.177 C 364.565 641.537 324.365 643.647 285.135 638.387 C 209.845 628.687 138.755 590.487 88.865 533.307 C 62.515 503.427 41.945 468.457 28.625 430.907 C 11.745 383.477 6.735 331.947 13.795 282.117 C 20.125 237.037 36.525 193.397 61.475 155.307 C 99.975 95.917 159.025 50.147 226.205 27.827 C 256.555 17.577 288.505 12.067 320.535 11.437 M 261.945 105.867 C 230.365 111.887 202.875 132.667 185.655 159.447 C 174.545 176.627 166.695 195.867 162.005 215.747 C 158.225 244.567 164.245 273.407 169.825 301.557 C 169.605 310.327 172.155 318.877 173.015 327.577 C 168.095 333.187 162.545 338.477 159.035 345.137 C 157.675 353.507 160.275 361.917 162.355 369.977 C 166.375 382.077 169.655 394.507 175.275 405.997 C 177.965 411.567 182.145 416.477 187.495 419.637 C 195.835 424.627 204.575 429.217 211.475 436.207 C 200.285 442.467 189.045 448.637 177.855 454.887 C 183.715 475.157 194.575 493.377 204.135 512.037 C 212.965 529.067 221.585 546.237 231.485 562.687 C 238.515 559.987 245.745 557.727 252.435 554.207 C 264.345 548.747 275.415 541.597 287.155 535.817 C 302.195 537.177 316.855 542.287 332.095 541.497 C 344.655 540.427 356.925 537.357 369.385 535.607 C 377.185 539.767 384.865 544.137 392.605 548.407 C 403.005 554.207 413.985 558.847 425.245 562.697 C 444.085 527.267 465.075 492.707 478.765 454.837 C 468.555 449.007 458.115 443.617 447.615 438.337 C 448.865 434.957 449.215 431.047 451.125 428.027 C 458.985 424.397 467.965 422.397 474.375 416.187 C 479.125 411.817 481.105 405.497 483.945 399.897 C 490.115 385.797 494.065 370.857 497.715 355.947 C 498.795 351.797 498.465 347.307 496.555 343.457 C 493.275 337.327 488.165 332.447 483.685 327.207 C 485.275 315.737 487.895 304.347 487.995 292.737 C 490.925 274.337 490.465 255.497 488.365 237.037 C 485.575 217.917 481.365 198.847 474.085 180.897 C 470.565 172.687 466.655 164.337 460.185 157.997 C 457.285 155.167 455.235 151.637 452.535 148.637 C 446.395 141.707 439.265 135.677 431.605 130.507 C 402.075 110.857 366.185 103.077 331.155 101.897 C 308.015 100.687 284.855 102.717 261.945 105.867 Z"/>
|
||||
<path fill="#000" stroke="#000" stroke-width="5" opacity="1.00" d="M 261.945 105.867 C 284.855 102.717 308.015 100.687 331.155 101.897 C 366.185 103.077 402.075 110.857 431.605 130.507 C 439.265 135.677 446.395 141.707 452.535 148.637 C 455.235 151.637 457.285 155.167 460.185 157.997 C 466.655 164.337 470.565 172.687 474.085 180.897 C 481.365 198.847 485.575 217.917 488.365 237.037 C 490.465 255.497 490.925 274.337 487.995 292.737 C 485.815 302.907 482.575 312.807 480.055 322.907 C 478.085 330.507 476.315 338.157 474.475 345.797 C 470.595 361.457 467.165 377.237 463.395 392.927 C 461.075 372.117 457.855 351.397 456.175 330.517 C 455.365 319.917 453.285 309.107 447.955 299.787 C 443.065 287.837 433.845 278.097 423.735 270.317 C 412.825 262.347 400.465 256.157 387.285 253.047 C 396.535 265.577 409.855 274.157 422.075 283.487 C 414.195 283.987 406.515 281.747 399.195 279.097 C 380.995 272.317 364.005 262.737 347.355 252.847 C 333.475 244.627 320.155 235.537 306.665 226.707 C 314.425 239.517 326.205 249.167 337.575 258.637 C 348.475 267.697 359.985 275.967 371.495 284.237 C 352.795 285.497 335.005 278.077 318.035 271.147 C 283.745 256.197 251.465 237.017 220.135 216.667 C 218.985 227.657 216.045 238.327 213.215 248.977 C 211.535 254.917 210.155 260.967 207.935 266.737 C 201.275 283.327 198.665 301.217 197.545 318.967 C 196.935 333.247 196.385 347.597 197.635 361.867 C 198.145 375.347 200.905 388.667 200.605 402.197 C 195.145 383.307 190.015 364.337 184.335 345.517 C 179.895 330.747 175.785 315.807 169.825 301.557 C 164.245 273.407 158.225 244.567 162.005 215.747 C 166.695 195.867 174.545 176.627 185.655 159.447 C 202.875 132.667 230.365 111.887 261.945 105.867 Z"/>
|
||||
<path fill="#7e0023" stroke="#7e0023" stroke-width="5" opacity="1.00" d="M 220.135 216.667 C 251.465 237.017 283.745 256.197 318.035 271.147 C 335.005 278.077 352.795 285.497 371.495 284.237 C 359.985 275.967 348.475 267.697 337.575 258.637 C 326.205 249.167 314.425 239.517 306.665 226.707 C 320.155 235.537 333.475 244.627 347.355 252.847 C 364.005 262.737 380.995 272.317 399.195 279.097 C 406.515 281.747 414.195 283.987 422.075 283.487 C 409.855 274.157 396.535 265.577 387.285 253.047 C 400.465 256.157 412.825 262.347 423.735 270.317 C 433.845 278.097 443.065 287.837 447.955 299.787 C 448.355 310.507 451.865 320.787 456.175 330.517 C 457.855 351.397 461.075 372.117 463.395 392.927 C 467.165 377.237 470.595 361.457 474.475 345.797 C 478.915 346.407 483.365 346.897 487.825 347.407 C 484.035 369.287 476.295 390.217 467.355 410.467 C 461.425 409.057 455.485 407.707 449.565 406.267 C 445.515 414.737 441.545 423.257 437.605 431.777 C 428.225 432.437 418.865 433.227 409.485 433.757 C 398.135 416.227 385.455 399.277 369.515 385.627 C 360.355 377.307 350.095 369.527 337.985 366.217 C 330.135 364.297 321.425 364.167 314.075 367.897 C 296.375 375.497 281.735 388.667 269.415 403.227 C 261.155 412.807 254.355 423.487 247.045 433.777 C 237.755 433.227 228.495 432.367 219.215 431.807 C 215.155 423.317 211.215 414.777 207.175 406.277 C 201.235 407.697 195.285 409.077 189.335 410.457 C 180.385 390.067 172.545 369.037 168.735 347.027 C 173.945 346.647 179.135 346.087 184.335 345.517 C 190.015 364.337 195.145 383.307 200.605 402.197 C 200.905 388.667 198.145 375.347 197.635 361.867 C 196.385 347.597 196.935 333.247 197.545 318.967 C 198.665 301.217 201.275 283.327 207.935 266.737 C 210.155 260.967 211.535 254.917 213.215 248.977 C 216.045 238.327 218.985 227.657 220.135 216.667 M 243.695 306.947 C 262.215 315.227 283.945 314.707 302.685 307.417 C 283.255 303.507 263.215 303.767 243.695 306.947 M 353.885 307.497 C 372.545 314.847 393.765 314.437 412.635 308.007 C 402.945 305.817 393.065 304.817 383.165 304.437 C 373.325 304.637 363.565 305.797 353.885 307.497 M 257.635 331.277 C 257.575 335.617 257.515 339.967 257.485 344.317 C 269.265 348.937 283.225 347.127 293.025 338.957 C 287.925 334.967 283.415 329.777 277.105 327.697 C 270.505 327.927 264.015 329.617 257.635 331.277 M 377.525 328.417 C 372.265 330.957 368.495 335.587 364.225 339.437 C 367.785 341.797 371.445 344.117 375.585 345.327 C 383.245 347.827 391.565 346.927 399.105 344.437 C 399.305 339.927 399.305 335.417 399.265 330.907 C 394.625 329.857 389.985 328.787 385.275 328.167 C 382.705 327.907 379.915 326.997 377.525 328.417 Z"/>
|
||||
<path fill="#000" stroke="#000" stroke-width="5" opacity="1.00" d="M 480.055 322.907 C 482.575 312.807 485.815 302.907 487.995 292.737 C 487.895 304.347 485.275 315.737 483.685 327.207 C 488.165 332.447 493.275 337.327 496.555 343.457 C 498.465 347.307 498.795 351.797 497.715 355.947 C 494.065 370.857 490.115 385.797 483.945 399.897 C 481.105 405.497 479.125 411.817 474.375 416.187 C 467.965 422.397 458.985 424.397 451.125 428.027 C 449.215 431.047 448.865 434.957 447.615 438.337 C 458.115 443.617 468.555 449.007 478.765 454.837 C 465.075 492.707 444.085 527.267 425.245 562.697 C 413.985 558.847 403.005 554.207 392.605 548.407 C 384.865 544.137 377.185 539.767 369.385 535.607 C 356.925 537.357 344.655 540.427 332.095 541.497 C 316.855 542.287 302.195 537.177 287.155 535.817 C 275.415 541.597 264.345 548.747 252.435 554.207 C 245.745 557.727 238.515 559.987 231.485 562.687 C 221.585 546.237 212.965 529.067 204.135 512.037 C 194.575 493.377 183.715 475.157 177.855 454.887 C 189.045 448.637 200.285 442.467 211.475 436.207 C 204.575 429.217 195.835 424.627 187.495 419.637 C 182.145 416.477 177.965 411.567 175.275 405.997 C 169.655 394.507 166.375 382.077 162.355 369.977 C 160.275 361.917 157.675 353.507 159.035 345.137 C 162.545 338.477 168.095 333.187 173.015 327.577 C 172.155 318.877 169.605 310.327 169.825 301.557 C 175.785 315.807 179.895 330.747 184.335 345.517 C 179.135 346.087 173.945 346.647 168.735 347.027 C 172.545 369.037 180.385 390.067 189.335 410.457 C 195.285 409.077 201.235 407.697 207.175 406.277 C 211.215 414.777 215.155 423.317 219.215 431.807 C 228.495 432.367 237.755 433.227 247.045 433.777 C 254.355 423.487 261.155 412.807 269.415 403.227 C 281.735 388.667 296.375 375.497 314.075 367.897 C 321.425 364.167 330.135 364.297 337.985 366.217 C 350.095 369.527 360.355 377.307 369.515 385.627 C 385.455 399.277 398.135 416.227 409.485 433.757 C 418.865 433.227 428.225 432.437 437.605 431.777 C 441.545 423.257 445.515 414.737 449.565 406.267 C 455.485 407.707 461.425 409.057 467.355 410.467 C 476.295 390.217 484.035 369.287 487.825 347.407 C 483.365 346.897 478.915 346.407 474.475 345.797 C 476.315 338.157 478.085 330.507 480.055 322.907 M 317.365 375.117 C 303.055 381.917 290.665 392.227 280.065 403.907 C 269.225 415.537 260.625 428.937 251.665 441.997 C 265.435 469.187 279.115 496.407 292.485 523.797 C 313.035 533.347 338.005 535.597 358.865 525.757 C 361.925 523.927 366.085 522.807 367.315 519.067 C 378.385 492.707 392.065 467.567 404.815 442.007 C 394.575 425.827 383.135 410.257 369.215 397.037 C 361.375 389.367 353.035 381.927 343.275 376.777 C 335.435 372.757 325.445 370.557 317.365 375.117 M 229.485 440.377 C 221.485 442.477 214.475 447.157 206.725 449.977 C 222.265 480.567 237.745 511.197 253.715 541.567 C 262.215 536.987 272.595 534.467 278.555 526.317 C 282.335 521.347 280.225 514.777 277.405 509.907 C 266.775 487.867 256.435 465.577 243.065 445.027 C 240.115 440.747 234.445 438.887 229.485 440.377 M 401.195 464.987 C 396.605 474.647 391.485 484.037 386.665 493.587 C 382.665 501.117 378.345 508.637 376.265 516.967 C 374.345 523.147 378.815 529.117 383.715 532.397 C 389.775 536.247 396.515 538.857 402.845 542.237 C 418.555 511.367 435.025 480.877 450.015 449.647 C 439.625 445.727 429.715 438.667 418.095 439.827 C 410.755 446.937 405.875 456.017 401.195 464.987 M 189.075 458.537 C 195.165 472.897 202.095 486.877 209.265 500.727 C 218.005 517.427 226.615 534.197 235.685 550.707 C 239.665 549.347 243.705 548.117 247.745 546.927 C 232.395 515.977 216.655 485.227 200.915 454.477 C 196.965 455.827 193.035 457.207 189.075 458.537 M 409.265 546.857 C 413.225 547.997 417.165 549.177 421.105 550.397 C 436.545 520.117 452.805 490.237 466.955 459.327 C 463.335 457.717 459.715 456.127 456.105 454.517 C 440.395 485.247 424.215 515.737 409.265 546.857 Z"/>
|
||||
<path fill="#000" stroke="#000" stroke-width="5" opacity="1.00" d="M 447.955 299.787 C 453.285 309.107 455.365 319.917 456.175 330.517 C 451.865 320.787 448.355 310.507 447.955 299.787 Z"/>
|
||||
<path fill="#000" stroke="#000" stroke-width="5" opacity="1.00" d="M 243.695 306.947 C 263.215 303.767 283.255 303.507 302.685 307.417 C 283.945 314.707 262.215 315.227 243.695 306.947 Z"/>
|
||||
<path fill="#000" stroke="#000" stroke-width="5" opacity="1.00" d="M 353.885 307.497 C 363.565 305.797 373.325 304.637 383.165 304.437 C 393.065 304.817 402.945 305.817 412.635 308.007 C 393.765 314.437 372.545 314.847 353.885 307.497 Z"/>
|
||||
<path fill="#000" stroke="#000" stroke-width="5" opacity="1.00" d="M 257.635 331.277 C 264.015 329.617 270.505 327.927 277.105 327.697 C 283.415 329.777 287.925 334.967 293.025 338.957 C 283.225 347.127 269.265 348.937 257.485 344.317 C 257.515 339.967 257.575 335.617 257.635 331.277 Z"/>
|
||||
<path fill="#000" stroke="#000" stroke-width="5" opacity="1.00" d="M 377.525 328.417 C 379.915 326.997 382.705 327.907 385.275 328.167 C 389.985 328.787 394.625 329.857 399.265 330.907 C 399.305 335.417 399.305 339.927 399.105 344.437 C 391.565 346.927 383.245 347.827 375.585 345.327 C 371.445 344.117 367.785 341.797 364.225 339.437 C 368.495 335.587 372.265 330.957 377.525 328.417 Z"/>
|
||||
<path fill="#7e0023" stroke="#7e0023" stroke-width="5" opacity="1.00" d="M 317.365 375.117 C 325.445 370.557 335.435 372.757 343.275 376.777 C 353.035 381.927 361.375 389.367 369.215 397.037 C 383.135 410.257 394.575 425.827 404.815 442.007 C 392.065 467.567 378.385 492.707 367.315 519.067 C 366.085 522.807 361.925 523.927 358.865 525.757 C 338.005 535.597 313.035 533.347 292.485 523.797 C 279.115 496.407 265.435 469.187 251.665 441.997 C 260.625 428.937 269.225 415.537 280.065 403.907 C 290.665 392.227 303.055 381.917 317.365 375.117 M 320.585 420.607 C 300.445 423.987 284.615 442.777 283.845 463.017 C 283.675 478.547 291.975 493.777 304.935 502.287 C 312.395 507.087 321.225 510.327 330.215 509.817 C 346.125 509.357 360.925 499.297 368.605 485.577 C 373.325 477.247 374.655 467.337 373.195 457.947 C 370.625 433.597 344.345 415.307 320.585 420.607 Z"/>
|
||||
<path fill="#000" stroke="#000" stroke-width="5" opacity="1.00" d="M 320.585 420.607 C 344.345 415.307 370.625 433.597 373.195 457.947 C 374.655 467.337 373.325 477.247 368.605 485.577 C 360.925 499.297 346.125 509.357 330.215 509.817 C 321.225 510.327 312.395 507.087 304.935 502.287 C 291.975 493.777 283.675 478.547 283.845 463.017 C 284.615 442.777 300.445 423.987 320.585 420.607 M 324.485 443.417 C 318.515 445.217 312.265 448.637 309.715 454.647 C 306.965 460.877 307.365 468.147 309.705 474.437 C 311.695 479.817 316.675 483.737 322.185 485.057 C 329.725 487.477 338.355 485.337 344.265 480.177 C 348.745 476.087 350.055 469.727 350.495 463.937 C 350.315 451.247 336.815 440.787 324.485 443.417 Z"/>
|
||||
<path fill="#7e0023" stroke="#7e0023" stroke-width="5" opacity="1.00" d="M 229.485 440.377 C 234.445 438.887 240.115 440.747 243.065 445.027 C 256.435 465.577 266.775 487.867 277.405 509.907 C 280.225 514.777 282.335 521.347 278.555 526.317 C 272.595 534.467 262.215 536.987 253.715 541.567 C 237.745 511.197 222.265 480.567 206.725 449.977 C 214.475 447.157 221.485 442.477 229.485 440.377 Z"/>
|
||||
<path fill="#7e0023" stroke="#7e0023" stroke-width="5" opacity="1.00" d="M 401.195 464.987 C 405.875 456.017 410.755 446.937 418.095 439.827 C 429.715 438.667 439.625 445.727 450.015 449.647 C 435.025 480.877 418.555 511.367 402.845 542.237 C 396.515 538.857 389.775 536.247 383.715 532.397 C 378.815 529.117 374.345 523.147 376.265 516.967 C 378.345 508.637 382.665 501.117 386.665 493.587 C 391.485 484.037 396.605 474.647 401.195 464.987 Z"/>
|
||||
<path fill="#7e0023" stroke="#7e0023" stroke-width="5" opacity="1.00" d="M 324.485 443.417 C 336.815 440.787 350.315 451.247 350.495 463.937 C 350.055 469.727 348.745 476.087 344.265 480.177 C 338.355 485.337 329.725 487.477 322.185 485.057 C 316.675 483.737 311.695 479.817 309.705 474.437 C 307.365 468.147 306.965 460.877 309.715 454.647 C 312.265 448.637 318.515 445.217 324.485 443.417 Z"/>
|
||||
<path fill="#7e0023" stroke="#7e0023" stroke-width="5" opacity="1.00" d="M 189.075 458.537 C 193.035 457.207 196.965 455.827 200.915 454.477 C 216.655 485.227 232.395 515.977 247.745 546.927 C 243.705 548.117 239.665 549.347 235.685 550.707 C 226.615 534.197 218.005 517.427 209.265 500.727 C 202.095 486.877 195.165 472.897 189.075 458.537 Z"/>
|
||||
<path fill="#7e0023" stroke="#7e0023" stroke-width="5" opacity="1.00" d="M 409.265 546.857 C 424.215 515.737 440.395 485.247 456.105 454.517 C 459.715 456.127 463.335 457.717 466.955 459.327 C 452.805 490.237 436.545 520.117 421.105 550.397 C 417.165 549.177 413.225 547.997 409.265 546.857 Z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 15 KiB |
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="moderate-air-quality" width="1024pt" height="1024pt" viewBox="0 0 650 650" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="#ffff00" stroke="#ffff00" stroke-width="2" opacity="1.00" d="M 306.143 12.125 C 349.223 9.135 392.903 15.025 433.623 29.385 C 471.263 42.665 506.383 63.115 536.423 89.395 C 593.563 138.785 632.063 209.375 641.783 284.345 C 650.263 346.445 639.623 411.065 611.263 466.985 C 588.543 512.235 554.663 551.805 513.573 581.365 C 465.893 615.905 408.383 636.675 349.623 640.475 C 307.233 643.405 264.223 637.835 224.063 623.905 C 153.253 599.745 91.793 549.415 54.083 484.805 C 33.383 449.715 19.703 410.505 14.083 370.155 C 7.803 325.485 11.193 279.455 24.183 236.255 C 35.883 197.155 55.413 160.445 81.143 128.775 C 109.873 93.325 146.343 64.175 187.283 44.015 C 224.303 25.725 264.943 14.805 306.143 12.125 M 256.393 98.485 C 231.103 104.515 208.583 119.915 192.323 140.045 C 175.843 160.115 165.253 184.365 158.433 209.235 C 157.343 213.885 155.703 218.405 155.603 223.245 C 153.403 236.825 155.313 250.535 156.203 264.135 C 157.733 278.795 160.913 293.215 163.223 307.765 C 164.383 318.965 166.643 330.075 168.173 341.255 C 164.183 344.785 159.333 347.335 155.763 351.325 C 152.073 355.435 153.433 361.265 153.563 366.265 C 155.443 382.635 161.873 397.965 167.473 413.325 C 169.643 419.515 173.303 425.215 178.413 429.365 C 184.623 435.015 192.703 437.605 200.493 440.235 C 217.353 475.275 238.823 508.805 268.133 534.745 C 275.113 540.525 281.793 546.995 290.313 550.495 C 305.483 556.815 322.313 557.785 338.553 556.995 C 353.393 556.165 368.733 552.605 380.683 543.335 C 415.123 516.455 439.753 479.195 458.553 440.215 C 468.003 437.385 477.563 433.455 484.183 425.835 C 490.383 419.355 492.363 410.345 495.623 402.265 C 500.903 387.505 506.543 372.205 505.603 356.265 C 503.893 348.845 495.933 345.985 490.873 341.205 C 494.603 317.035 499.053 292.765 498.213 268.205 C 498.253 254.515 496.033 240.965 493.023 227.655 L 492.483 227.165 C 489.283 211.515 485.763 195.795 479.993 180.855 C 475.643 170.025 470.963 158.665 462.073 150.695 C 455.643 140.715 446.953 132.375 437.523 125.245 C 420.383 112.515 400.393 104.085 379.743 99.055 C 339.363 89.145 297.033 91.595 256.393 98.485 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="2" opacity="1.00" d="M 256.393 98.485 C 297.033 91.595 339.363 89.145 379.743 99.055 C 400.393 104.085 420.383 112.515 437.523 125.245 C 446.953 132.375 455.643 140.715 462.073 150.695 C 470.963 158.665 475.643 170.025 479.993 180.855 C 485.763 195.795 489.283 211.515 492.483 227.165 C 492.783 232.225 493.873 237.195 494.483 242.215 C 495.883 258.845 497.463 275.595 495.413 292.255 C 494.653 307.635 489.383 322.215 486.323 337.195 C 484.933 343.775 483.543 350.365 482.153 356.945 C 478.373 375.115 474.383 393.265 471.163 411.535 C 467.903 391.795 466.073 371.865 463.153 352.075 C 462.423 346.205 462.743 340.195 461.343 334.415 C 458.113 325.155 456.093 315.495 452.453 306.375 C 444.903 291.125 432.313 278.715 417.753 270.085 C 409.073 265.065 399.823 260.655 389.963 258.625 C 393.763 264.695 399.283 269.435 404.533 274.215 C 411.163 279.975 418.163 285.305 425.203 290.555 L 425.443 291.565 C 413.923 292.155 403.093 287.315 392.673 283.025 C 365.803 270.735 340.863 254.665 316.513 238.035 C 313.383 235.935 310.473 233.465 307.033 231.875 C 307.783 234.345 309.303 236.475 310.803 238.555 C 321.223 251.285 333.873 261.915 346.563 272.305 C 355.533 279.535 364.763 286.435 374.093 293.205 C 366.163 294.485 358.253 292.625 350.493 291.155 C 326.223 284.575 303.583 273.235 281.533 261.355 C 259.063 249.045 237.313 235.485 216.043 221.225 C 215.233 231.455 212.693 241.445 210.663 251.485 C 208.323 259.905 206.893 268.575 204.033 276.855 C 199.353 289.185 197.333 302.285 195.443 315.285 C 194.193 331.565 192.893 347.905 193.883 364.245 C 194.563 374.615 194.953 385.015 196.013 395.365 C 197.043 402.945 198.023 410.535 198.213 418.195 C 197.863 418.645 197.163 419.555 196.813 420.005 C 191.053 399.015 185.103 378.095 178.913 357.225 C 176.073 347.485 173.133 337.765 169.803 328.185 C 167.973 322.805 166.063 317.425 164.903 311.845 C 164.633 310.375 164.013 309.005 163.223 307.765 C 160.913 293.215 157.733 278.795 156.203 264.135 C 155.313 250.535 153.403 236.825 155.603 223.245 C 155.703 218.405 157.343 213.885 158.433 209.235 C 165.253 184.365 175.843 160.115 192.323 140.045 C 208.583 119.915 231.103 104.515 256.393 98.485 Z"/>
|
||||
<path fill="#ffff00" stroke="#ffff00" stroke-width="2" opacity="1.00" d="M 216.043 221.225 C 237.313 235.485 259.063 249.045 281.533 261.355 C 303.583 273.235 326.223 284.575 350.493 291.155 C 358.253 292.625 366.163 294.485 374.093 293.205 C 364.763 286.435 355.533 279.535 346.563 272.305 C 333.873 261.915 321.223 251.285 310.803 238.555 C 312.663 238.075 314.593 237.985 316.513 238.035 C 340.863 254.665 365.803 270.735 392.673 283.025 C 403.093 287.315 413.923 292.155 425.443 291.565 L 425.203 290.555 C 418.163 285.305 411.163 279.975 404.533 274.215 C 399.283 269.435 393.763 264.695 389.963 258.625 C 399.823 260.655 409.073 265.065 417.753 270.085 C 432.313 278.715 444.903 291.125 452.453 306.375 C 456.093 315.495 458.113 325.155 461.343 334.415 C 462.743 340.195 462.423 346.205 463.153 352.075 C 466.073 371.865 467.903 391.795 471.163 411.535 C 474.383 393.265 478.373 375.115 482.153 356.945 C 486.953 357.055 491.763 357.215 496.573 357.415 C 491.993 380.715 487.673 405.715 471.553 424.205 C 466.643 422.325 461.813 420.245 456.893 418.415 C 444.513 445.885 431.043 473.215 412.223 496.925 C 403.443 507.755 394.043 518.145 383.593 527.385 C 376.153 534.455 367.353 540.215 357.663 543.655 C 345.053 547.645 331.543 548.365 318.443 547.185 C 306.403 545.975 294.553 542.065 284.623 535.065 C 249.783 507.735 225.163 469.595 207.103 429.625 C 205.283 425.925 203.993 421.925 201.863 418.415 C 201.073 418.745 199.513 419.415 198.723 419.745 C 198.593 419.355 198.343 418.585 198.213 418.195 C 198.023 410.535 197.043 402.945 196.013 395.365 C 194.953 385.015 194.563 374.615 193.883 364.245 C 192.893 347.905 194.193 331.565 195.443 315.285 C 197.333 302.285 199.353 289.185 204.033 276.855 C 206.893 268.575 208.323 259.905 210.663 251.485 C 212.693 241.445 215.233 231.455 216.043 221.225 M 242.153 316.475 C 248.643 320.145 256.073 321.845 263.413 322.875 C 275.963 324.215 289.053 322.625 300.463 317.035 L 300.613 316.335 C 281.183 314.445 261.573 314.395 242.153 316.475 M 358.043 316.575 C 367.033 321.405 377.493 323.015 387.613 323.295 C 397.613 323.095 408.063 321.565 416.823 316.505 C 397.293 314.345 377.573 314.515 358.043 316.575 M 264.893 339.775 C 261.573 340.625 258.853 342.865 255.953 344.595 C 253.473 348.035 255.793 352.645 258.593 355.115 C 261.203 357.885 265.223 357.055 268.523 358.265 C 276.563 359.445 284.073 354.695 289.213 348.915 C 289.863 347.875 291.753 347.285 291.283 345.835 C 283.043 342.295 274.123 337.285 264.893 339.775 M 368.093 345.375 C 368.863 349.305 372.593 351.825 375.623 354.165 C 381.783 357.845 389.593 359.485 396.503 357.025 C 401.263 355.275 404.143 350.395 404.353 345.465 C 400.223 340.825 393.693 338.815 387.583 339.255 C 380.633 339.515 374.333 342.635 368.093 345.375 M 308.583 406.395 C 312.153 409.815 316.703 412.115 321.523 413.145 C 330.843 415.315 340.343 413.025 349.403 410.745 C 349.393 410.485 349.383 409.955 349.383 409.695 C 336.563 403.885 322.183 406.175 308.583 406.395 M 283.243 463.925 C 293.423 466.725 303.983 467.775 314.523 467.565 C 331.213 467.455 347.983 468.315 364.603 466.405 C 368.153 465.415 372.283 465.295 375.463 463.655 C 367.893 460.435 359.653 459.575 351.533 459.025 C 336.543 458.865 321.563 458.815 306.573 459.045 C 298.663 459.775 290.503 460.385 283.243 463.925 M 313.333 482.135 C 313.663 484.975 314.063 487.795 314.453 490.625 C 322.003 490.625 329.633 490.795 337.123 489.635 C 341.413 488.675 346.253 487.405 349.413 484.345 C 337.483 482.415 325.383 482.365 313.333 482.135 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="2" opacity="1.00" d="M 492.483 227.165 L 493.023 227.655 C 496.033 240.965 498.253 254.515 498.213 268.205 C 499.053 292.765 494.603 317.035 490.873 341.205 C 495.933 345.985 503.893 348.845 505.603 356.265 C 506.543 372.205 500.903 387.505 495.623 402.265 C 492.363 410.345 490.383 419.355 484.183 425.835 C 477.563 433.455 468.003 437.385 458.553 440.215 C 439.753 479.195 415.123 516.455 380.683 543.335 C 368.733 552.605 353.393 556.165 338.553 556.995 C 322.313 557.785 305.483 556.815 290.313 550.495 C 281.793 546.995 275.113 540.525 268.133 534.745 C 238.823 508.805 217.353 475.275 200.493 440.235 C 192.703 437.605 184.623 435.015 178.413 429.365 C 173.303 425.215 169.643 419.515 167.473 413.325 C 161.873 397.965 155.443 382.635 153.563 366.265 C 153.433 361.265 152.073 355.435 155.763 351.325 C 159.333 347.335 164.183 344.785 168.173 341.255 C 166.643 330.075 164.383 318.965 163.223 307.765 C 164.013 309.005 164.633 310.375 164.903 311.845 C 166.063 317.425 167.973 322.805 169.803 328.185 C 173.133 337.765 176.073 347.485 178.913 357.225 C 173.373 357.075 167.843 356.735 162.303 356.615 C 165.873 374.065 168.823 391.975 176.683 408.115 C 179.613 413.925 183.273 419.325 187.583 424.205 C 190.583 422.705 194.253 422.185 196.813 420.005 C 197.163 419.555 197.863 418.645 198.213 418.195 C 198.343 418.585 198.593 419.355 198.723 419.745 C 199.513 419.415 201.073 418.745 201.863 418.415 C 203.993 421.925 205.283 425.925 207.103 429.625 C 225.163 469.595 249.783 507.735 284.623 535.065 C 294.553 542.065 306.403 545.975 318.443 547.185 C 331.543 548.365 345.053 547.645 357.663 543.655 C 367.353 540.215 376.153 534.455 383.593 527.385 C 394.043 518.145 403.443 507.755 412.223 496.925 C 431.043 473.215 444.513 445.885 456.893 418.415 C 461.813 420.245 466.643 422.325 471.553 424.205 C 487.673 405.715 491.993 380.715 496.573 357.415 C 491.763 357.215 486.953 357.055 482.153 356.945 C 483.543 350.365 484.933 343.775 486.323 337.195 C 489.383 322.215 494.653 307.635 495.413 292.255 C 497.463 275.595 495.883 258.845 494.483 242.215 C 493.873 237.195 492.783 232.225 492.483 227.165 M 197.593 420.415 C 196.903 421.595 197.003 424.205 198.193 424.865 C 198.543 423.615 199.423 420.645 197.593 420.415 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="2" opacity="1.00" d="M 307.033 231.875 C 310.473 233.465 313.383 235.935 316.513 238.035 C 314.593 237.985 312.663 238.075 310.803 238.555 C 309.303 236.475 307.783 234.345 307.033 231.875 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="2" opacity="1.00" d="M 242.153 316.475 C 261.573 314.395 281.183 314.445 300.613 316.335 L 300.463 317.035 C 289.053 322.625 275.963 324.215 263.413 322.875 C 256.073 321.845 248.643 320.145 242.153 316.475 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="2" opacity="1.00" d="M 358.043 316.575 C 377.573 314.515 397.293 314.345 416.823 316.505 C 408.063 321.565 397.613 323.095 387.613 323.295 C 377.493 323.015 367.033 321.405 358.043 316.575 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="2" opacity="1.00" d="M 264.893 339.775 C 274.123 337.285 283.043 342.295 291.283 345.835 C 291.753 347.285 289.863 347.875 289.213 348.915 C 284.073 354.695 276.563 359.445 268.523 358.265 C 265.223 357.055 261.203 357.885 258.593 355.115 C 255.793 352.645 253.473 348.035 255.953 344.595 C 258.853 342.865 261.573 340.625 264.893 339.775 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="2" opacity="1.00" d="M 368.093 345.375 C 374.333 342.635 380.633 339.515 387.583 339.255 C 393.693 338.815 400.223 340.825 404.353 345.465 C 404.143 350.395 401.263 355.275 396.503 357.025 C 389.593 359.485 381.783 357.845 375.623 354.165 C 372.593 351.825 368.863 349.305 368.093 345.375 Z"/>
|
||||
<path fill="#ffff00" stroke="#ffff00" stroke-width="2" opacity="1.00" d="M 162.303 356.615 C 167.843 356.735 173.373 357.075 178.913 357.225 C 185.103 378.095 191.053 399.015 196.813 420.005 C 194.253 422.185 190.583 422.705 187.583 424.205 C 183.273 419.325 179.613 413.925 176.683 408.115 C 168.823 391.975 165.873 374.065 162.303 356.615 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="2" opacity="1.00" d="M 308.583 406.395 C 322.183 406.175 336.563 403.885 349.383 409.695 C 349.383 409.955 349.393 410.485 349.403 410.745 C 340.343 413.025 330.843 415.315 321.523 413.145 C 316.703 412.115 312.153 409.815 308.583 406.395 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="2" opacity="1.00" d="M 197.593 420.415 C 199.423 420.645 198.543 423.615 198.193 424.865 C 197.003 424.205 196.903 421.595 197.593 420.415 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="2" opacity="1.00" d="M 283.243 463.925 C 290.503 460.385 298.663 459.775 306.573 459.045 C 321.563 458.815 336.543 458.865 351.533 459.025 C 359.653 459.575 367.893 460.435 375.463 463.655 C 372.283 465.295 368.153 465.415 364.603 466.405 C 347.983 468.315 331.213 467.455 314.523 467.565 C 303.983 467.775 293.423 466.725 283.243 463.925 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="2" opacity="1.00" d="M 313.333 482.135 C 325.383 482.365 337.483 482.415 349.413 484.345 C 346.253 487.405 341.413 488.675 337.123 489.635 C 329.633 490.795 322.003 490.625 314.453 490.625 C 314.063 487.795 313.663 484.975 313.333 482.135 Z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 13 KiB |
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="unhealthy-air-quality" width="1024pt" height="1024pt" viewBox="0 0 650 650" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="#ff0000" stroke="#ff0000" stroke-width="5" opacity="1.00" d="M 303.023 8.993 C 349.903 5.933 397.483 13.243 441.123 30.683 C 515.803 60.023 578.303 118.983 611.753 191.933 C 645.123 263.373 649.693 347.603 624.553 422.303 C 607.123 474.953 575.213 522.623 533.553 559.183 C 494.063 593.983 445.783 618.773 394.413 630.293 C 317.923 647.853 234.993 635.933 166.883 596.823 C 100.763 559.523 48.853 497.613 24.213 425.763 C 7.893 378.993 3.173 328.313 10.073 279.293 C 16.463 233.443 33.323 189.123 58.903 150.553 C 78.103 121.503 102.133 95.633 129.743 74.393 C 179.253 35.943 240.463 12.863 303.023 8.993 M 251.533 117.223 C 232.073 121.183 213.863 130.603 199.063 143.803 C 174.963 165.113 160.223 195.183 152.533 226.023 C 149.973 243.353 151.333 261.003 153.923 278.243 C 154.813 285.863 156.613 293.353 157.213 301.023 C 158.493 315.503 161.273 329.793 163.343 344.173 C 159.383 347.803 154.563 350.533 151.213 354.783 C 148.013 358.843 148.963 364.313 149.213 369.093 C 150.783 383.533 156.013 397.213 160.913 410.783 C 163.203 417.553 165.983 424.453 171.333 429.433 C 177.603 435.933 186.163 439.283 194.603 441.953 C 202.633 458.533 211.333 474.823 221.513 490.203 C 232.373 506.593 245.393 521.483 259.663 534.993 C 270.073 544.623 282.533 552.893 296.843 554.963 C 316.423 557.973 337.293 558.373 355.823 550.433 C 365.003 546.653 372.503 540.003 379.763 533.413 C 407.303 507.973 427.503 475.663 443.373 441.953 C 448.383 440.103 453.613 438.693 458.193 435.863 C 465.503 431.613 471.683 425.123 474.623 417.103 C 478.023 408.133 481.243 399.083 484.223 389.963 C 486.953 379.943 489.873 369.623 488.743 359.143 C 486.923 352.013 479.513 348.843 474.633 344.073 C 478.263 320.603 482.493 297.043 481.893 273.193 C 481.913 256.623 479.053 240.163 474.443 224.283 C 470.303 207.713 465.613 190.893 456.383 176.343 C 453.423 171.423 448.713 167.953 445.593 163.153 C 434.143 148.663 418.373 138.153 401.763 130.433 C 401.673 129.983 401.483 129.073 401.393 128.623 C 399.743 129.023 398.063 128.983 396.533 128.233 C 381.453 121.783 365.393 117.993 349.243 115.433 C 316.803 111.073 283.833 112.403 251.533 117.223 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="5" opacity="1.00" d="M 251.533 117.223 C 283.833 112.403 316.803 111.073 349.243 115.433 C 365.393 117.993 381.453 121.783 396.533 128.233 C 398.063 128.983 399.743 129.023 401.393 128.623 C 401.483 129.073 401.673 129.983 401.763 130.433 C 418.373 138.153 434.143 148.663 445.593 163.153 C 448.713 167.953 453.423 171.423 456.383 176.343 C 465.613 190.893 470.303 207.713 474.443 224.283 C 479.053 240.163 481.913 256.623 481.893 273.193 C 482.493 297.043 478.263 320.603 474.633 344.073 C 479.513 348.843 486.923 352.013 488.743 359.143 C 489.873 369.623 486.953 379.943 484.223 389.963 C 481.243 399.083 478.023 408.133 474.623 417.103 C 471.683 425.123 465.503 431.613 458.193 435.863 C 453.613 438.693 448.383 440.103 443.373 441.953 C 427.503 475.663 407.303 507.973 379.763 533.413 C 372.503 540.003 365.003 546.653 355.823 550.433 C 337.293 558.373 316.423 557.973 296.843 554.963 C 282.533 552.893 270.073 544.623 259.663 534.993 C 245.393 521.483 232.373 506.593 221.513 490.203 C 211.333 474.823 202.633 458.533 194.603 441.953 C 186.163 439.283 177.603 435.933 171.333 429.433 C 165.983 424.453 163.203 417.553 160.913 410.783 C 156.013 397.213 150.783 383.533 149.213 369.093 C 148.963 364.313 148.013 358.843 151.213 354.783 C 154.563 350.533 159.383 347.803 163.343 344.173 C 161.273 329.793 158.493 315.503 157.213 301.023 C 156.613 293.353 154.813 285.863 153.923 278.243 C 151.333 261.003 149.973 243.353 152.533 226.023 C 160.223 195.183 174.963 165.113 199.063 143.803 C 213.863 130.603 232.073 121.183 251.533 117.223 M 210.493 227.813 C 209.643 236.653 207.483 245.283 205.263 253.863 C 202.683 263.083 200.683 272.503 196.983 281.373 C 191.973 295.273 189.443 309.983 188.343 324.693 C 186.223 350.823 187.293 377.173 191.053 403.083 C 194.163 413.243 198.593 422.943 202.463 432.833 C 226.413 425.023 246.353 409.083 267.823 396.463 C 279.353 389.893 291.393 383.763 304.533 381.243 C 320.323 377.783 336.923 380.633 351.623 386.953 C 380.983 399.633 404.823 422.833 435.473 432.833 C 439.953 421.133 444.593 409.493 449.013 397.773 C 450.073 394.313 451.903 390.883 451.553 387.163 C 450.183 371.103 447.083 355.203 446.453 339.083 C 444.833 331.173 441.663 323.673 439.673 315.853 C 436.823 303.603 428.173 293.793 419.093 285.553 C 407.183 275.473 392.933 267.933 377.733 264.283 C 386.883 276.813 400.213 285.363 412.413 294.623 C 407.233 295.133 402.103 294.133 397.133 292.743 C 383.463 288.773 370.623 282.393 358.103 275.693 C 340.363 266.113 323.273 255.383 306.533 244.163 C 304.793 242.763 302.523 243.073 300.463 243.073 C 305.193 249.653 311.183 255.173 317.093 260.663 C 331.263 273.173 346.433 284.493 361.863 295.403 C 347.333 296.653 333.163 291.893 319.723 286.943 C 297.583 278.413 276.493 267.413 255.883 255.723 C 240.503 246.833 225.263 237.673 210.493 227.813 M 164.053 355.223 C 162.073 361.963 160.363 369.023 161.323 376.083 C 162.393 382.283 164.683 388.183 166.503 394.183 C 169.683 404.133 173.133 414.523 180.533 422.213 C 183.243 425.173 186.693 427.283 190.143 429.283 C 181.953 404.423 174.343 379.323 164.053 355.223 M 447.743 429.243 C 454.513 424.973 461.633 420.023 464.783 412.353 C 468.583 402.043 472.753 391.833 475.543 381.193 C 477.663 372.583 477.343 363.353 473.863 355.143 C 463.073 379.063 455.713 404.293 447.743 429.243 M 290.893 394.553 C 261.713 408.423 236.703 430.043 206.293 441.473 C 223.603 476.883 245.893 511.023 277.543 535.253 C 303.003 551.233 338.133 550.963 362.823 533.523 C 393.043 509.153 414.813 476.033 431.633 441.423 C 404.793 431.363 382.083 413.373 357.133 399.693 C 349.933 395.973 342.743 392.013 334.823 390.083 C 320.253 386.333 304.393 387.923 290.893 394.553 Z"/>
|
||||
<path fill="#ff0000" stroke="#ff0000" stroke-width="5" opacity="1.00" d="M 210.493 227.813 C 225.263 237.673 240.503 246.833 255.883 255.723 C 276.493 267.413 297.583 278.413 319.723 286.943 C 333.163 291.893 347.333 296.653 361.863 295.403 C 346.433 284.493 331.263 273.173 317.093 260.663 C 311.183 255.173 305.193 249.653 300.463 243.073 C 302.523 243.073 304.793 242.763 306.533 244.163 C 323.273 255.383 340.363 266.113 358.103 275.693 C 370.623 282.393 383.463 288.773 397.133 292.743 C 402.103 294.133 407.233 295.133 412.413 294.623 C 400.213 285.363 386.883 276.813 377.733 264.283 C 392.933 267.933 407.183 275.473 419.093 285.553 C 428.173 293.793 436.823 303.603 439.673 315.853 C 441.663 323.673 444.833 331.173 446.453 339.083 C 447.083 355.203 450.183 371.103 451.553 387.163 C 451.903 390.883 450.073 394.313 449.013 397.773 C 444.593 409.493 439.953 421.133 435.473 432.833 C 404.823 422.833 380.983 399.633 351.623 386.953 C 336.923 380.633 320.323 377.783 304.533 381.243 C 291.393 383.763 279.353 389.893 267.823 396.463 C 246.353 409.083 226.413 425.023 202.463 432.833 C 198.593 422.943 194.163 413.243 191.053 403.083 C 187.293 377.173 186.223 350.823 188.343 324.693 C 189.443 309.983 191.973 295.273 196.983 281.373 C 200.683 272.503 202.683 263.083 205.263 253.863 C 207.483 245.283 209.643 236.653 210.493 227.813 M 233.533 320.473 C 250.363 328.833 269.573 325.373 287.613 325.633 C 287.743 323.333 287.883 321.033 288.033 318.743 C 269.853 318.703 251.603 318.003 233.533 320.473 M 350.343 318.793 C 350.293 321.093 350.253 323.393 350.213 325.703 C 368.443 325.833 386.793 326.603 404.863 323.573 C 387.623 316.153 368.533 319.023 350.343 318.793 M 248.953 347.643 C 246.223 350.563 247.123 355.233 249.623 357.993 C 254.273 360.823 260.043 361.503 265.363 360.633 C 272.443 359.443 278.533 355.003 283.023 349.553 C 276.613 346.913 270.403 343.363 263.453 342.393 C 258.243 342.193 252.573 343.723 248.953 347.643 M 355.533 348.993 C 360.833 358.343 373.133 363.653 383.243 359.113 C 388.493 357.083 391.873 352.203 393.523 347.013 C 381.483 341.523 366.833 341.793 355.533 348.993 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="5" opacity="1.00" d="M 233.533 320.473 C 251.603 318.003 269.853 318.703 288.033 318.743 C 287.883 321.033 287.743 323.333 287.613 325.633 C 269.573 325.373 250.363 328.833 233.533 320.473 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="5" opacity="1.00" d="M 350.343 318.793 C 368.533 319.023 387.623 316.153 404.863 323.573 C 386.793 326.603 368.443 325.833 350.213 325.703 C 350.253 323.393 350.293 321.093 350.343 318.793 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="5" opacity="1.00" d="M 248.953 347.643 C 252.573 343.723 258.243 342.193 263.453 342.393 C 270.403 343.363 276.613 346.913 283.023 349.553 C 278.533 355.003 272.443 359.443 265.363 360.633 C 260.043 361.503 254.273 360.823 249.623 357.993 C 247.123 355.233 246.223 350.563 248.953 347.643 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="5" opacity="1.00" d="M 355.533 348.993 C 366.833 341.793 381.483 341.523 393.523 347.013 C 391.873 352.203 388.493 357.083 383.243 359.113 C 373.133 363.653 360.833 358.343 355.533 348.993 Z"/>
|
||||
<path fill="#ff0000" stroke="#ff0000" stroke-width="5" opacity="1.00" d="M 164.053 355.223 C 174.343 379.323 181.953 404.423 190.143 429.283 C 186.693 427.283 183.243 425.173 180.533 422.213 C 173.133 414.523 169.683 404.133 166.503 394.183 C 164.683 388.183 162.393 382.283 161.323 376.083 C 160.363 369.023 162.073 361.963 164.053 355.223 Z"/>
|
||||
<path fill="#ff0000" stroke="#ff0000" stroke-width="5" opacity="1.00" d="M 447.743 429.243 C 455.713 404.293 463.073 379.063 473.863 355.143 C 477.343 363.353 477.663 372.583 475.543 381.193 C 472.753 391.833 468.583 402.043 464.783 412.353 C 461.633 420.023 454.513 424.973 447.743 429.243 Z"/>
|
||||
<path fill="#ff0000" stroke="#ff0000" stroke-width="5" opacity="1.00" d="M 290.893 394.553 C 304.393 387.923 320.253 386.333 334.823 390.083 C 342.743 392.013 349.933 395.973 357.133 399.693 C 382.083 413.373 404.793 431.363 431.633 441.423 C 414.813 476.033 393.043 509.153 362.823 533.523 C 338.133 550.963 303.003 551.233 277.543 535.253 C 245.893 511.023 223.603 476.883 206.293 441.473 C 236.703 430.043 261.713 408.423 290.893 394.553 M 273.033 447.823 C 283.293 453.293 295.283 452.943 306.573 452.953 C 326.123 452.673 345.903 453.823 365.173 449.763 C 359.523 445.593 352.593 443.473 345.603 443.333 C 330.583 443.123 315.543 443.663 300.523 443.193 C 291.183 442.983 281.623 443.913 273.033 447.823 M 280.833 464.783 C 278.863 467.923 276.873 471.053 274.893 474.193 C 304.223 476.393 333.693 476.403 363.023 474.153 C 361.023 471.013 359.023 467.883 356.993 464.773 C 331.613 464.803 306.223 464.773 280.833 464.783 M 271.573 491.723 C 301.863 490.923 332.173 491.793 362.463 490.773 C 354.723 488.243 346.573 487.443 338.473 487.243 C 327.503 487.183 316.523 487.013 305.543 487.083 C 294.113 487.183 282.413 487.713 271.573 491.723 M 280.083 493.493 C 280.033 495.003 279.993 496.523 279.963 498.043 C 307.443 496.733 335.473 501.683 362.463 494.403 C 335.013 493.183 307.533 494.363 280.083 493.493 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="5" opacity="1.00" d="M 273.033 447.823 C 281.623 443.913 291.183 442.983 300.523 443.193 C 315.543 443.663 330.583 443.123 345.603 443.333 C 352.593 443.473 359.523 445.593 365.173 449.763 C 345.903 453.823 326.123 452.673 306.573 452.953 C 295.283 452.943 283.293 453.293 273.033 447.823 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="5" opacity="1.00" d="M 280.833 464.783 C 306.223 464.773 331.613 464.803 356.993 464.773 C 359.023 467.883 361.023 471.013 363.023 474.153 C 333.693 476.403 304.223 476.393 274.893 474.193 C 276.873 471.053 278.863 467.923 280.833 464.783 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="5" opacity="1.00" d="M 271.573 491.723 C 282.413 487.713 294.113 487.183 305.543 487.083 C 316.523 487.013 327.503 487.183 338.473 487.243 C 346.573 487.443 354.723 488.243 362.463 490.773 C 332.173 491.793 301.863 490.923 271.573 491.723 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="5" opacity="1.00" d="M 280.083 493.493 C 307.533 494.363 335.013 493.183 362.463 494.403 C 335.473 501.683 307.443 496.733 279.963 498.043 C 279.993 496.523 280.033 495.003 280.083 493.493 Z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="unhealthy-quality" width="1024pt" height="1024pt" viewBox="0 0 650 650" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="#ff7e00" stroke="#ff7e00" stroke-width="2" opacity="1.00" d="M 316.007 10.138 C 365.027 8.368 414.467 18.068 459.067 38.548 C 527.987 69.788 584.957 126.638 615.997 195.688 C 648.837 267.368 652.787 351.658 627.067 426.158 C 609.427 478.148 577.627 525.168 536.297 561.258 C 494.117 598.318 441.897 623.838 386.707 634.208 C 347.267 641.698 306.427 641.658 266.997 634.138 C 227.337 626.568 189.137 611.328 155.237 589.408 C 91.907 548.938 43.757 485.178 22.867 412.928 C 9.577 367.808 6.837 319.678 14.507 273.288 C 22.177 226.838 40.597 182.208 67.887 143.848 C 105.807 90.048 160.967 48.618 223.237 27.278 C 253.057 16.948 284.457 11.178 316.007 10.138 M 255.587 118.688 C 224.477 124.618 197.317 144.868 180.077 171.088 C 168.797 188.048 161.007 207.168 155.977 226.868 C 153.627 240.738 154.337 254.918 155.677 268.868 C 157.787 285.748 160.497 302.648 165.477 318.958 C 168.377 327.558 171.397 336.118 173.957 344.828 C 170.237 347.618 166.507 350.398 162.767 353.138 C 163.757 371.798 169.497 389.818 176.717 406.928 C 178.677 412.158 181.347 417.278 185.567 421.048 C 191.317 426.668 199.077 429.348 206.767 431.078 C 220.607 458.998 237.387 485.888 259.667 507.888 C 269.417 517.388 279.667 527.128 292.637 531.998 C 310.907 538.938 331.087 538.488 350.027 534.928 C 361.767 533.168 371.887 526.298 380.857 518.908 C 408.707 495.088 429.427 464.048 445.367 431.298 C 452.687 429.408 460.147 427.018 465.887 421.868 C 470.687 417.958 473.577 412.328 475.707 406.628 C 482.027 391.298 487.707 375.428 489.347 358.838 C 488.787 350.678 480.767 346.408 475.227 341.608 C 476.447 333.658 477.377 325.668 478.877 317.768 C 481.317 306.898 483.257 295.858 483.427 284.688 C 483.907 256.938 479.977 229.018 471.117 202.678 C 466.737 190.428 461.587 177.848 451.917 168.768 C 444.337 158.048 434.357 149.218 423.387 142.098 C 394.167 123.378 359.097 115.848 324.787 114.718 C 301.647 113.508 278.497 115.558 255.587 118.688 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="2" opacity="1.00" d="M 255.587 118.688 C 278.497 115.558 301.647 113.508 324.787 114.718 C 359.097 115.848 394.167 123.378 423.387 142.098 C 434.357 149.218 444.337 158.048 451.917 168.768 C 461.587 177.848 466.737 190.428 471.117 202.678 C 479.977 229.018 483.907 256.938 483.427 284.688 C 483.257 295.858 481.317 306.898 478.877 317.768 C 477.377 325.668 476.447 333.658 475.227 341.608 C 480.767 346.408 488.787 350.678 489.347 358.838 C 487.707 375.428 482.027 391.298 475.707 406.628 C 473.577 412.328 470.687 417.958 465.887 421.868 C 460.147 427.018 452.687 429.408 445.367 431.298 C 429.427 464.048 408.707 495.088 380.857 518.908 C 371.887 526.298 361.767 533.168 350.027 534.928 C 331.087 538.488 310.907 538.938 292.637 531.998 C 279.667 527.128 269.417 517.388 259.667 507.888 C 237.387 485.888 220.607 458.998 206.767 431.078 C 199.077 429.348 191.317 426.668 185.567 421.048 C 181.347 417.278 178.677 412.158 176.717 406.928 C 169.497 389.818 163.757 371.798 162.767 353.138 C 166.507 350.398 170.237 347.618 173.957 344.828 C 171.397 336.118 168.377 327.558 165.477 318.958 C 160.497 302.648 157.787 285.748 155.677 268.868 C 154.337 254.918 153.627 240.738 155.977 226.868 C 161.007 207.168 168.797 188.048 180.077 171.088 C 197.317 144.868 224.477 124.618 255.587 118.688 M 213.767 229.428 C 212.917 238.278 210.747 246.918 208.537 255.508 C 205.977 264.718 203.937 274.118 200.267 282.968 C 191.987 305.938 190.597 330.668 190.637 354.878 C 190.187 364.538 191.397 374.148 191.827 383.788 C 193.027 393.998 194.377 404.228 194.217 414.538 C 188.537 395.428 183.287 376.178 177.687 357.038 C 176.237 357.148 174.787 357.288 173.337 357.418 C 177.017 378.618 182.937 400.058 195.787 417.688 C 199.167 415.808 202.307 413.478 205.837 411.888 C 209.217 411.298 210.897 414.948 212.197 417.398 C 219.497 432.458 226.687 447.648 235.977 461.618 C 247.227 479.218 260.827 495.288 276.347 509.268 C 288.657 521.228 305.857 527.158 322.817 527.628 C 337.567 528.238 352.557 524.818 365.357 517.388 C 399.227 492.628 422.317 456.188 439.537 418.528 C 440.837 415.858 442.077 411.808 445.777 412.088 C 449.927 412.568 453.307 415.388 456.617 417.708 C 469.367 400.028 475.387 378.618 478.967 357.388 C 475.457 357.248 471.947 357.128 468.447 357.048 C 464.537 373.278 460.837 389.558 457.067 405.818 C 454.517 384.878 451.837 363.908 449.487 342.978 C 444.507 331.258 441.297 318.928 437.587 306.788 C 435.817 300.178 430.587 295.388 426.057 290.588 C 413.577 278.618 397.787 269.978 380.987 265.928 C 390.167 278.428 403.487 286.898 415.597 296.258 C 409.847 296.828 404.217 295.438 398.727 293.908 C 382.877 288.868 368.047 281.118 353.577 273.008 C 335.267 262.778 317.817 251.108 300.337 239.538 C 305.417 248.368 312.937 255.398 320.347 262.258 C 334.507 274.778 349.687 286.088 365.117 297.008 C 350.907 298.278 337.017 293.648 323.847 288.878 C 300.297 279.878 277.927 268.108 256.097 255.578 C 241.777 247.198 227.547 238.658 213.767 229.428 Z"/>
|
||||
<path fill="#ff7e00" stroke="#ff7e00" stroke-width="2" opacity="1.00" d="M 213.767 229.428 C 227.547 238.658 241.777 247.198 256.097 255.578 C 277.927 268.108 300.297 279.878 323.847 288.878 C 337.017 293.648 350.907 298.278 365.117 297.008 C 349.687 286.088 334.507 274.778 320.347 262.258 C 312.937 255.398 305.417 248.368 300.337 239.538 C 317.817 251.108 335.267 262.778 353.577 273.008 C 368.047 281.118 382.877 288.868 398.727 293.908 C 404.217 295.438 409.847 296.828 415.597 296.258 C 403.487 286.898 390.167 278.428 380.987 265.928 C 397.787 269.978 413.577 278.618 426.057 290.588 C 430.587 295.388 435.817 300.178 437.587 306.788 C 441.297 318.928 444.507 331.258 449.487 342.978 C 451.837 363.908 454.517 384.878 457.067 405.818 C 460.837 389.558 464.537 373.278 468.447 357.048 C 471.947 357.128 475.457 357.248 478.967 357.388 C 475.387 378.618 469.367 400.028 456.617 417.708 C 453.307 415.388 449.927 412.568 445.777 412.088 C 442.077 411.808 440.837 415.858 439.537 418.528 C 422.317 456.188 399.227 492.628 365.357 517.388 C 352.557 524.818 337.567 528.238 322.817 527.628 C 305.857 527.158 288.657 521.228 276.347 509.268 C 260.827 495.288 247.227 479.218 235.977 461.618 C 226.687 447.648 219.497 432.458 212.197 417.398 C 210.897 414.948 209.217 411.298 205.837 411.888 C 202.307 413.478 199.167 415.808 195.787 417.688 C 182.937 400.058 177.017 378.618 173.337 357.418 C 174.787 357.288 176.237 357.148 177.687 357.038 C 183.287 376.178 188.537 395.428 194.217 414.538 C 194.377 404.228 193.027 393.998 191.827 383.788 C 191.397 374.148 190.187 364.538 190.637 354.878 C 190.597 330.668 191.987 305.938 200.267 282.968 C 203.937 274.118 205.977 264.718 208.537 255.508 C 210.747 246.918 212.917 238.278 213.767 229.428 M 353.377 306.828 C 353.787 312.018 356.257 316.998 360.497 320.108 C 367.557 325.448 376.287 327.918 384.707 330.218 C 393.307 332.498 403.637 332.038 410.137 325.228 C 390.197 323.228 370.427 317.548 353.377 306.828 M 242.157 325.388 C 249.517 332.278 260.507 332.448 269.707 329.828 C 278.177 327.268 286.757 324.288 293.927 318.958 C 297.427 316.398 298.407 311.868 297.447 307.808 C 280.747 318.018 261.497 323.288 242.157 325.388 M 360.847 346.958 C 364.727 352.768 370.837 357.288 377.867 358.218 C 383.897 359.168 390.097 356.548 394.327 352.328 C 397.347 346.888 391.447 341.228 386.317 340.188 C 377.197 336.748 368.547 342.818 360.847 346.958 M 258.357 345.288 C 255.937 347.838 257.647 351.728 259.807 353.838 C 263.557 358.018 269.587 358.578 274.857 358.458 C 281.887 357.678 287.117 352.278 291.877 347.538 C 285.827 343.598 279.337 339.448 271.857 339.378 C 266.697 339.188 262.147 342.108 258.357 345.288 M 306.407 404.408 C 318.897 409.698 333.187 409.168 345.737 404.368 C 333.757 397.708 318.307 397.458 306.407 404.408 M 296.117 451.248 C 289.937 454.298 285.107 459.638 282.497 465.998 C 290.487 463.408 298.177 460.058 305.927 456.878 C 315.207 453.068 325.637 451.878 335.427 454.328 C 345.637 457.148 355.007 462.238 365.047 465.538 C 363.967 460.968 361.677 456.588 357.737 453.868 C 349.627 448.028 339.347 446.728 329.717 445.308 C 318.327 445.238 306.437 445.938 296.117 451.248 M 314.597 468.138 C 313.317 470.968 311.987 473.778 310.647 476.578 C 321.977 476.488 333.407 476.588 344.547 474.188 C 336.007 467.768 324.747 468.198 314.597 468.138 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="2" opacity="1.00" d="M 353.377 306.828 C 370.427 317.548 390.197 323.228 410.137 325.228 C 403.637 332.038 393.307 332.498 384.707 330.218 C 376.287 327.918 367.557 325.448 360.497 320.108 C 356.257 316.998 353.787 312.018 353.377 306.828 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="2" opacity="1.00" d="M 242.157 325.388 C 261.497 323.288 280.747 318.018 297.447 307.808 C 298.407 311.868 297.427 316.398 293.927 318.958 C 286.757 324.288 278.177 327.268 269.707 329.828 C 260.507 332.448 249.517 332.278 242.157 325.388 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="2" opacity="1.00" d="M 360.847 346.958 C 368.547 342.818 377.197 336.748 386.317 340.188 C 391.447 341.228 397.347 346.888 394.327 352.328 C 390.097 356.548 383.897 359.168 377.867 358.218 C 370.837 357.288 364.727 352.768 360.847 346.958 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="2" opacity="1.00" d="M 258.357 345.288 C 262.147 342.108 266.697 339.188 271.857 339.378 C 279.337 339.448 285.827 343.598 291.877 347.538 C 287.117 352.278 281.887 357.678 274.857 358.458 C 269.587 358.578 263.557 358.018 259.807 353.838 C 257.647 351.728 255.937 347.838 258.357 345.288 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="2" opacity="1.00" d="M 306.407 404.408 C 318.307 397.458 333.757 397.708 345.737 404.368 C 333.187 409.168 318.897 409.698 306.407 404.408 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="2" opacity="1.00" d="M 296.117 451.248 C 306.437 445.938 318.327 445.238 329.717 445.308 C 339.347 446.728 349.627 448.028 357.737 453.868 C 361.677 456.588 363.967 460.968 365.047 465.538 C 355.007 462.238 345.637 457.148 335.427 454.328 C 325.637 451.878 315.207 453.068 305.927 456.878 C 298.177 460.058 290.487 463.408 282.497 465.998 C 285.107 459.638 289.937 454.298 296.117 451.248 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="2" opacity="1.00" d="M 314.597 468.138 C 324.747 468.198 336.007 467.768 344.547 474.188 C 333.407 476.588 321.977 476.488 310.647 476.578 C 311.987 473.778 313.317 470.968 314.597 468.138 Z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 10 KiB |
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="very-unhealthy-air-quality" width="1024pt" height="1024pt" viewBox="0 0 650 650" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="#8f3f97" stroke="#8f3f97" stroke-width="5" opacity="1.00" d="M 300.083 11.549 C 347.253 8.309 395.173 15.619 439.103 33.159 C 514.263 62.689 577.103 122.209 610.383 195.809 C 643.173 266.889 647.513 350.449 622.613 424.629 C 606.063 474.649 576.483 520.209 537.843 555.989 C 497.623 593.389 447.513 620.139 393.953 632.419 C 317.053 650.489 233.473 638.689 164.913 599.319 C 98.763 562.009 46.833 500.079 22.193 428.189 C 6.673 383.679 1.643 335.599 7.173 288.809 C 13.093 237.599 32.123 188.019 61.783 145.879 C 82.163 116.789 107.493 91.169 136.343 70.459 C 183.983 36.019 241.423 15.349 300.083 11.549 M 249.023 119.819 C 217.703 126.189 190.603 147.069 173.613 173.779 C 162.863 190.519 155.313 209.219 150.543 228.499 C 147.973 245.849 149.343 263.519 151.933 280.779 C 153.663 294.469 156.893 307.909 160.213 321.289 C 160.563 329.609 162.703 337.709 163.933 345.919 C 160.273 346.809 156.623 347.719 152.973 348.629 C 151.123 352.809 149.393 357.129 149.183 361.759 C 148.183 373.589 153.473 384.539 156.943 395.529 C 160.213 404.479 162.293 414.209 168.503 421.739 C 174.643 429.729 184.133 434.769 194.123 435.819 C 195.883 439.569 197.633 443.309 199.393 447.059 C 189.283 452.009 178.803 456.389 169.703 463.129 C 167.823 472.959 174.333 481.389 178.453 489.709 C 189.523 510.279 200.563 530.869 211.643 551.439 C 213.813 555.219 215.863 559.159 218.823 562.399 C 221.183 565.019 225.113 565.869 228.393 564.599 C 245.273 558.149 261.143 549.289 276.383 539.629 C 300.873 547.699 327.633 547.929 352.523 541.469 C 354.323 541.039 356.253 540.469 358.063 541.239 C 364.713 543.359 370.823 546.829 376.793 550.389 C 388.273 557.189 400.373 564.749 414.233 564.369 C 420.103 556.959 424.893 548.789 429.073 540.319 C 433.413 531.689 438.233 523.299 442.653 514.709 C 450.453 500.119 459.193 485.919 465.153 470.449 C 465.973 465.309 462.283 460.629 458.153 458.049 C 450.973 453.669 442.633 451.669 435.423 447.329 C 437.173 443.499 438.943 439.689 440.743 435.889 C 448.463 433.639 457.183 432.189 462.933 426.069 C 473.333 413.899 477.103 397.929 482.043 383.089 C 483.723 377.379 486.513 371.779 486.153 365.679 C 486.163 359.759 484.203 354.089 482.083 348.629 C 478.383 347.709 474.673 346.789 470.973 345.879 C 472.823 334.399 475.513 322.969 475.993 311.339 C 479.283 290.599 479.173 269.359 476.173 248.589 C 473.573 229.899 469.403 211.289 462.133 193.819 C 458.673 185.849 454.793 177.779 448.493 171.629 C 445.623 168.809 443.573 165.289 440.883 162.309 C 430.373 150.439 417.063 141.329 402.883 134.399 C 383.013 124.839 361.333 119.429 339.483 116.979 C 309.373 113.789 278.913 115.269 249.023 119.819 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="5" opacity="1.00" d="M 249.023 119.819 C 278.913 115.269 309.373 113.789 339.483 116.979 C 361.333 119.429 383.013 124.839 402.883 134.399 C 417.063 141.329 430.373 150.439 440.883 162.309 C 443.573 165.289 445.623 168.809 448.493 171.629 C 454.793 177.779 458.673 185.849 462.133 193.819 C 469.403 211.289 473.573 229.899 476.173 248.589 C 479.173 269.359 479.283 290.599 475.993 311.339 C 470.223 326.619 467.053 342.729 463.063 358.529 C 459.103 374.529 455.583 390.639 451.763 406.669 C 449.353 384.999 446.003 363.419 444.293 341.689 C 443.703 338.669 442.523 335.829 441.513 332.949 C 439.073 326.289 437.333 319.399 435.233 312.639 C 432.863 304.199 426.733 297.569 420.773 291.449 C 408.273 279.429 392.443 270.879 375.633 266.719 C 384.893 279.259 398.223 287.859 410.463 297.189 C 400.983 297.729 391.843 294.519 383.163 291.099 C 359.233 281.269 337.073 267.719 315.363 253.789 C 310.383 250.849 305.823 245.919 299.473 247.059 C 309.493 259.269 321.893 269.189 334.203 278.969 C 342.573 285.549 351.253 291.719 359.893 297.939 C 341.113 299.189 323.253 291.719 306.223 284.759 C 272.003 269.809 239.763 250.689 208.503 230.339 C 206.573 246.459 201.813 262.079 197.313 277.629 C 192.083 290.439 188.913 303.999 187.213 317.719 C 185.143 337.949 184.553 358.389 186.193 378.669 C 186.893 391.129 189.253 403.469 188.993 415.989 C 183.523 396.949 178.313 377.839 172.613 358.869 C 168.733 346.269 165.513 333.389 160.213 321.289 C 156.893 307.909 153.663 294.469 151.933 280.779 C 149.343 263.519 147.973 245.849 150.543 228.499 C 155.313 209.219 162.863 190.519 173.613 173.779 C 190.603 147.069 217.703 126.189 249.023 119.819 Z"/>
|
||||
<path fill="#8f3f97" stroke="#8f3f97" stroke-width="5" opacity="1.00" d="M 208.503 230.339 C 239.763 250.689 272.003 269.809 306.223 284.759 C 323.253 291.719 341.113 299.189 359.893 297.939 C 351.253 291.719 342.573 285.549 334.203 278.969 C 321.893 269.189 309.493 259.269 299.473 247.059 C 305.823 245.919 310.383 250.849 315.363 253.789 C 337.073 267.719 359.233 281.269 383.163 291.099 C 391.843 294.519 400.983 297.729 410.463 297.189 C 398.223 287.859 384.893 279.259 375.633 266.719 C 392.443 270.879 408.273 279.429 420.773 291.449 C 426.733 297.569 432.863 304.199 435.233 312.639 C 437.333 319.399 439.073 326.289 441.513 332.949 C 442.523 335.829 443.703 338.669 444.293 341.689 C 446.003 363.419 449.353 384.999 451.763 406.669 C 455.583 390.639 459.103 374.529 463.063 358.529 C 467.343 358.489 471.633 358.459 475.913 358.459 C 473.013 381.029 466.753 403.889 452.703 422.219 C 448.333 420.059 443.963 417.889 439.603 415.729 C 434.833 424.119 430.433 432.709 426.253 441.419 C 417.003 441.799 407.783 442.559 398.593 443.699 C 389.763 431.309 381.043 418.759 370.313 407.899 C 359.843 397.019 347.773 387.579 334.253 380.789 C 324.943 376.319 313.743 375.419 304.073 379.269 C 286.643 386.819 271.753 399.259 259.273 413.429 C 250.723 422.889 243.483 433.399 235.953 443.669 C 226.903 442.629 217.843 441.769 208.743 441.339 C 204.473 432.629 199.973 424.029 195.153 415.609 C 190.833 417.799 186.523 420.009 182.213 422.209 C 168.103 403.889 162.193 380.929 158.693 358.469 C 163.333 358.579 167.973 358.719 172.613 358.869 C 178.313 377.839 183.523 396.949 188.993 415.989 C 189.253 403.469 186.893 391.129 186.193 378.669 C 184.553 358.389 185.143 337.949 187.213 317.719 C 188.913 303.999 192.083 290.439 197.313 277.629 C 201.813 262.079 206.573 246.459 208.503 230.339 M 234.203 320.169 C 237.943 323.989 243.113 326.109 248.453 326.229 C 258.123 326.549 267.843 326.839 277.503 326.039 C 282.443 325.689 287.103 323.639 290.893 320.499 C 272.053 318.679 253.063 318.749 234.203 320.169 M 344.613 320.389 C 348.133 323.749 352.733 325.879 357.623 326.139 C 366.903 326.779 376.213 326.499 385.513 326.289 C 391.133 326.319 396.773 324.369 400.593 320.129 C 381.963 318.769 363.223 318.729 344.613 320.389 M 247.853 347.059 C 245.843 349.249 245.823 352.989 248.113 354.999 C 256.863 362.969 272.733 361.829 279.123 351.399 C 274.653 338.879 255.993 337.739 247.853 347.059 M 360.933 344.029 C 356.753 346.619 355.923 353.219 359.693 356.499 C 368.973 362.419 383.073 361.259 389.633 351.779 C 388.003 346.079 382.853 342.119 377.073 341.309 C 371.633 340.429 365.683 341.089 360.933 344.029 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="5" opacity="1.00" d="M 463.063 358.529 C 467.053 342.729 470.223 326.619 475.993 311.339 C 475.513 322.969 472.823 334.399 470.973 345.879 C 474.673 346.789 478.383 347.709 482.083 348.629 C 484.203 354.089 486.163 359.759 486.153 365.679 C 486.513 371.779 483.723 377.379 482.043 383.089 C 477.103 397.929 473.333 413.899 462.933 426.069 C 457.183 432.189 448.463 433.639 440.743 435.889 C 438.943 439.689 437.173 443.499 435.423 447.329 C 442.633 451.669 450.973 453.669 458.153 458.049 C 462.283 460.629 465.973 465.309 465.153 470.449 C 459.193 485.919 450.453 500.119 442.653 514.709 C 438.233 523.299 433.413 531.689 429.073 540.319 C 424.893 548.789 420.103 556.959 414.233 564.369 C 400.373 564.749 388.273 557.189 376.793 550.389 C 370.823 546.829 364.713 543.359 358.063 541.239 C 356.253 540.469 354.323 541.039 352.523 541.469 C 327.633 547.929 300.873 547.699 276.383 539.629 C 261.143 549.289 245.273 558.149 228.393 564.599 C 225.113 565.869 221.183 565.019 218.823 562.399 C 215.863 559.159 213.813 555.219 211.643 551.439 C 200.563 530.869 189.523 510.279 178.453 489.709 C 174.333 481.389 167.823 472.959 169.703 463.129 C 178.803 456.389 189.283 452.009 199.393 447.059 C 197.633 443.309 195.883 439.569 194.123 435.819 C 184.133 434.769 174.643 429.729 168.503 421.739 C 162.293 414.209 160.213 404.479 156.943 395.529 C 153.473 384.539 148.183 373.589 149.183 361.759 C 149.393 357.129 151.123 352.809 152.973 348.629 C 156.623 347.719 160.273 346.809 163.933 345.919 C 162.703 337.709 160.563 329.609 160.213 321.289 C 165.513 333.389 168.733 346.269 172.613 358.869 C 167.973 358.719 163.333 358.579 158.693 358.469 C 162.193 380.929 168.103 403.889 182.213 422.209 C 186.523 420.009 190.833 417.799 195.153 415.609 C 199.973 424.029 204.473 432.629 208.743 441.339 C 217.843 441.769 226.903 442.629 235.953 443.669 C 243.483 433.399 250.723 422.889 259.273 413.429 C 271.753 399.259 286.643 386.819 304.073 379.269 C 313.743 375.419 324.943 376.319 334.253 380.789 C 347.773 387.579 359.843 397.019 370.313 407.899 C 381.043 418.759 389.763 431.309 398.593 443.699 C 407.783 442.559 417.003 441.799 426.253 441.419 C 430.433 432.709 434.833 424.119 439.603 415.729 C 443.963 417.889 448.333 420.059 452.703 422.219 C 466.753 403.889 473.013 381.029 475.913 358.459 C 471.633 358.459 467.343 358.489 463.063 358.529 M 298.463 390.529 C 274.033 405.129 255.543 427.709 240.823 451.699 C 246.073 461.639 251.233 471.639 256.883 481.359 C 265.553 496.429 273.713 511.979 278.303 528.839 C 302.823 540.149 332.173 540.199 356.663 528.779 C 361.093 511.329 369.763 495.399 378.683 479.889 C 384.033 470.719 388.843 461.249 393.793 451.869 C 381.893 430.849 365.293 412.809 346.773 397.449 C 337.943 390.769 327.983 384.119 316.503 383.959 C 309.833 383.639 303.933 387.169 298.463 390.529 M 196.013 458.459 C 211.563 488.339 226.933 518.329 244.073 547.339 C 249.953 544.159 256.043 541.339 261.793 537.919 C 266.833 534.869 271.103 529.249 270.133 523.079 C 266.983 515.199 263.033 507.649 259.043 500.159 C 251.843 486.749 244.923 473.189 237.323 459.999 C 234.463 454.879 230.193 450.549 224.793 448.149 C 214.573 449.559 205.363 454.389 196.013 458.459 M 405.723 449.769 C 397.523 456.799 393.213 467.059 388.213 476.369 C 380.673 491.429 371.533 505.709 365.253 521.379 C 362.693 527.749 366.873 534.619 372.303 537.949 C 378.343 541.619 384.843 544.479 391.163 547.659 C 398.893 533.579 406.643 519.519 414.383 505.449 C 422.673 489.769 430.753 473.979 438.943 458.249 C 433.303 455.989 427.823 453.379 422.253 450.969 C 417.103 448.969 410.993 447.499 405.723 449.769 M 444.903 462.209 C 429.983 492.229 411.743 520.599 399.013 551.689 C 402.663 553.099 406.323 554.489 410.003 555.859 C 425.213 526.849 440.563 497.899 456.023 469.019 C 452.323 466.739 448.623 464.459 444.903 462.209 M 178.223 466.099 C 191.563 496.969 209.003 525.779 224.683 555.469 C 228.933 554.359 233.173 553.249 237.423 552.139 C 222.553 522.089 206.343 492.739 190.843 463.009 C 186.633 464.029 182.423 465.059 178.223 466.099 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="5" opacity="1.00" d="M 234.203 320.169 C 253.063 318.749 272.053 318.679 290.893 320.499 C 287.103 323.639 282.443 325.689 277.503 326.039 C 267.843 326.839 258.123 326.549 248.453 326.229 C 243.113 326.109 237.943 323.989 234.203 320.169 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="5" opacity="1.00" d="M 344.613 320.389 C 363.223 318.729 381.963 318.769 400.593 320.129 C 396.773 324.369 391.133 326.319 385.513 326.289 C 376.213 326.499 366.903 326.779 357.623 326.139 C 352.733 325.879 348.133 323.749 344.613 320.389 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="5" opacity="1.00" d="M 247.853 347.059 C 255.993 337.739 274.653 338.879 279.123 351.399 C 272.733 361.829 256.863 362.969 248.113 354.999 C 245.823 352.989 245.843 349.249 247.853 347.059 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="5" opacity="1.00" d="M 360.933 344.029 C 365.683 341.089 371.633 340.429 377.073 341.309 C 382.853 342.119 388.003 346.079 389.633 351.779 C 383.073 361.259 368.973 362.419 359.693 356.499 C 355.923 353.219 356.753 346.619 360.933 344.029 Z"/>
|
||||
<path fill="#8f3f97" stroke="#8f3f97" stroke-width="5" opacity="1.00" d="M 298.463 390.529 C 303.933 387.169 309.833 383.639 316.503 383.959 C 327.983 384.119 337.943 390.769 346.773 397.449 C 365.293 412.809 381.893 430.849 393.793 451.869 C 388.843 461.249 384.033 470.719 378.683 479.889 C 369.763 495.399 361.093 511.329 356.663 528.779 C 332.173 540.199 302.823 540.149 278.303 528.839 C 273.713 511.979 265.553 496.429 256.883 481.359 C 251.233 471.639 246.073 461.639 240.823 451.699 C 255.543 427.709 274.033 405.129 298.463 390.529 M 310.003 430.329 C 295.753 433.049 282.913 442.809 276.953 456.099 C 273.643 463.299 273.063 471.489 273.963 479.279 C 277.963 503.119 304.253 520.699 327.793 514.839 C 340.503 511.489 351.913 502.939 358.153 491.299 C 363.253 481.889 363.353 470.549 360.783 460.379 C 354.493 439.599 331.083 426.479 310.003 430.329 Z"/>
|
||||
<path fill="#555" stroke="#555" stroke-width="5" opacity="1.00" d="M 310.003 430.329 C 331.083 426.479 354.493 439.599 360.783 460.379 C 363.353 470.549 363.253 481.889 358.153 491.299 C 351.913 502.939 340.503 511.489 327.793 514.839 C 304.253 520.699 277.963 503.119 273.963 479.279 C 273.063 471.489 273.643 463.299 276.953 456.099 C 282.913 442.809 295.753 433.049 310.003 430.329 M 312.873 452.229 C 307.023 454.129 300.883 457.529 298.453 463.509 C 296.103 469.269 296.403 475.869 298.443 481.679 C 300.213 486.889 304.903 490.749 310.113 492.249 C 318.233 494.889 327.833 493.169 334.083 487.219 C 338.033 483.119 339.353 477.169 339.703 471.679 C 339.173 458.859 325.063 449.339 312.873 452.229 Z"/>
|
||||
<path fill="#8f3f97" stroke="#8f3f97" stroke-width="5" opacity="1.00" d="M 196.013 458.459 C 205.363 454.389 214.573 449.559 224.793 448.149 C 230.193 450.549 234.463 454.879 237.323 459.999 C 244.923 473.189 251.843 486.749 259.043 500.159 C 263.033 507.649 266.983 515.199 270.133 523.079 C 271.103 529.249 266.833 534.869 261.793 537.919 C 256.043 541.339 249.953 544.159 244.073 547.339 C 226.933 518.329 211.563 488.339 196.013 458.459 Z"/>
|
||||
<path fill="#8f3f97" stroke="#8f3f97" stroke-width="5" opacity="1.00" d="M 405.723 449.769 C 410.993 447.499 417.103 448.969 422.253 450.969 C 427.823 453.379 433.303 455.989 438.943 458.249 C 430.753 473.979 422.673 489.769 414.383 505.449 C 406.643 519.519 398.893 533.579 391.163 547.659 C 384.843 544.479 378.343 541.619 372.303 537.949 C 366.873 534.619 362.693 527.749 365.253 521.379 C 371.533 505.709 380.673 491.429 388.213 476.369 C 393.213 467.059 397.523 456.799 405.723 449.769 Z"/>
|
||||
<path fill="#8f3f97" stroke="#8f3f97" stroke-width="5" opacity="1.00" d="M 312.873 452.229 C 325.063 449.339 339.173 458.859 339.703 471.679 C 339.353 477.169 338.033 483.119 334.083 487.219 C 327.833 493.169 318.233 494.889 310.113 492.249 C 304.903 490.749 300.213 486.889 298.443 481.679 C 296.403 475.869 296.103 469.269 298.453 463.509 C 300.883 457.529 307.023 454.129 312.873 452.229 Z"/>
|
||||
<path fill="#8f3f97" stroke="#8f3f97" stroke-width="5" opacity="1.00" d="M 444.903 462.209 C 448.623 464.459 452.323 466.739 456.023 469.019 C 440.563 497.899 425.213 526.849 410.003 555.859 C 406.323 554.489 402.663 553.099 399.013 551.689 C 411.743 520.599 429.983 492.229 444.903 462.209 Z"/>
|
||||
<path fill="#8f3f97" stroke="#8f3f97" stroke-width="5" opacity="1.00" d="M 178.223 466.099 C 182.423 465.059 186.633 464.029 190.843 463.009 C 206.343 492.739 222.553 522.089 237.423 552.139 C 233.173 553.249 228.933 554.359 224.683 555.469 C 209.003 525.779 191.563 496.969 178.223 466.099 Z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 16 KiB |
Loading…
Reference in New Issue