Created
August 6, 2025 19:04
-
-
Save bruvv/9e54aa40410d99ecc8e3ea7e15305066 to your computer and use it in GitHub Desktop.
M5 AirQ esphome
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| substitutions: | |
| devicename: lounge-airq | |
| friendlyname: Lounge AirQ | |
| location: Lounge | |
| sensor_interval: 10s | |
| esphome: | |
| name: ${devicename} | |
| friendly_name: ${friendlyname} | |
| area: ${location} | |
| platformio_options: | |
| board_build.mcu: esp32s3 | |
| board_build.name: "M5Stack StampS3" | |
| board_build.upload.flash_size: 8MB | |
| board_build.upload.maximum_size: 8388608 | |
| board_build.vendor: M5Stack | |
| on_boot: | |
| - priority: 800 | |
| then: | |
| - output.turn_on: enable | |
| - priority: 800 | |
| then: | |
| - pcf8563.read_time | |
| esp32: | |
| board: esp32-s3-devkitc-1 #m5stack-stamps3 | |
| variant: esp32s3 | |
| framework: | |
| type: arduino | |
| # Enable logging | |
| logger: | |
| # Enable Home Assistant API | |
| api: | |
| encryption: | |
| key: REDACTED | |
| ota: | |
| - platform: esphome | |
| password: REDACTED | |
| wifi: | |
| ssid: !secret wifi_ssid | |
| password: !secret wifi_password | |
| # Enable fallback hotspot (captive portal) in case wifi connection fails | |
| ap: | |
| ssid: "Lounge-Airq Fallback Hotspot" | |
| password: REDACTED | |
| captive_portal: | |
| output: | |
| - platform: gpio | |
| pin: GPIO10 | |
| id: enable | |
| web_server: | |
| port: 80 | |
| include_internal: true | |
| i2c: | |
| sda: GPIO11 | |
| scl: GPIO12 | |
| scan: true | |
| frequency: 100kHz | |
| id: bus_a | |
| spi: | |
| clk_pin: GPIO05 | |
| mosi_pin: GPIO06 | |
| time: | |
| - platform: pcf8563 | |
| address: 0x51 | |
| update_interval: 10min | |
| - platform: homeassistant | |
| id: esptime | |
| light: | |
| - platform: esp32_rmt_led_strip | |
| rgb_order: GRB | |
| pin: GPIO21 | |
| num_leds: 1 | |
| rmt_channel: 0 | |
| chipset: SK6812 | |
| name: "LED" | |
| restore_mode: ALWAYS_OFF | |
| id: id_led | |
| text_sensor: | |
| - platform: wifi_info | |
| ip_address: | |
| name: IP | |
| ssid: | |
| name: SSID | |
| bssid: | |
| name: BSSID | |
| mac_address: | |
| name: MAC | |
| dns_address: | |
| name: DNS | |
| - platform: template | |
| name: "VOC IAQ Classification" | |
| id: iaq_voc | |
| icon: "mdi:checkbox-marked-circle-outline" | |
| lambda: |- | |
| if (int(id(voc).state) < 100.0) { | |
| return {"Great"}; | |
| } | |
| else if (int(id(voc).state) <= 200.0) { | |
| return {"Good"}; | |
| } | |
| else if (int(id(voc).state) <= 300.0) { | |
| return {"Light"}; | |
| } | |
| else if (int(id(voc).state) <= 400.0) { | |
| return {"Moderate"}; | |
| } | |
| else if (int(id(voc).state) <= 500.0) { | |
| return {"Heavy"}; | |
| } | |
| else { | |
| return {"unknown"}; | |
| } | |
| - platform: template | |
| name: "NOX IAQ Classification" | |
| id: iaq_nox | |
| icon: "mdi:checkbox-marked-circle-outline" | |
| lambda: |- | |
| if (int(id(nox).state) < 100.0) { | |
| return {"Great"}; | |
| } | |
| else if (int(id(nox).state) <= 200.0) { | |
| return {"Good"}; | |
| } | |
| else if (int(id(nox).state) <= 300.0) { | |
| return {"Light"}; | |
| } | |
| else if (int(id(nox).state) <= 400.0) { | |
| return {"Moderate"}; | |
| } | |
| else if (int(id(nox).state) <= 500.0) { | |
| return {"Heavy"}; | |
| } | |
| else { | |
| return {"unknown"}; | |
| } | |
| sensor: | |
| - platform: scd4x | |
| co2: | |
| name: CO2 | |
| id: CO2 | |
| filters: | |
| - lambda: |- | |
| float MIN_VALUE = 300.0; | |
| float MAX_VALUE = 2500.0; | |
| if (MIN_VALUE <= x && x <= MAX_VALUE) return x; | |
| else return {}; | |
| temperature: | |
| name: CO2 Temperature | |
| id: CO2_temperature | |
| filters: | |
| - lambda: |- | |
| float MIN_VALUE = -40.0; | |
| float MAX_VALUE = 100.0; | |
| if (MIN_VALUE <= x && x <= MAX_VALUE) return x; | |
| else return {}; | |
| humidity: | |
| name: CO2 Humidity | |
| id: CO2_humidity | |
| filters: | |
| - lambda: |- | |
| float MIN_VALUE = 0.0; | |
| float MAX_VALUE = 100.0; | |
| if (MIN_VALUE <= x && x <= MAX_VALUE) return x; | |
| else return {}; | |
| altitude_compensation: 0m | |
| address: 0x62 | |
| update_interval: $sensor_interval | |
| - platform: wifi_signal # Reports the WiFi signal strength/RSSI in dB | |
| name: "Wifi Signal dB" | |
| id: wifi_signal_db | |
| update_interval: 60s | |
| entity_category: "diagnostic" | |
| - platform: sen5x | |
| id: sen55 | |
| pm_1_0: | |
| name: "PM 1" | |
| id: PM1_0 | |
| accuracy_decimals: 2 | |
| pm_2_5: | |
| name: "PM 2.5" | |
| id: PM2_5 | |
| accuracy_decimals: 2 | |
| pm_4_0: | |
| name: "PM 4" | |
| id: PM4_0 | |
| accuracy_decimals: 2 | |
| pm_10_0: | |
| name: "PM 10" | |
| id: PM10_0 | |
| accuracy_decimals: 2 | |
| temperature: | |
| name: "SEN55 Temperature" | |
| id: sen55_temperature | |
| accuracy_decimals: 2 | |
| humidity: | |
| name: "SEN55 Humidity" | |
| id: sen55_humidity | |
| accuracy_decimals: 2 | |
| voc: | |
| name: VOC | |
| id: voc | |
| accuracy_decimals: 2 | |
| algorithm_tuning: | |
| index_offset: 100 | |
| learning_time_offset_hours: 12 | |
| learning_time_gain_hours: 12 | |
| gating_max_duration_minutes: 180 | |
| std_initial: 50 | |
| gain_factor: 230 | |
| nox: | |
| name: NOX | |
| id: nox | |
| accuracy_decimals: 2 | |
| algorithm_tuning: | |
| index_offset: 100 | |
| learning_time_offset_hours: 12 | |
| learning_time_gain_hours: 12 | |
| gating_max_duration_minutes: 180 | |
| std_initial: 50 | |
| gain_factor: 230 | |
| temperature_compensation: | |
| offset: 0 | |
| normalized_offset_slope: 0 | |
| time_constant: 0 | |
| acceleration_mode: low | |
| store_baseline: true | |
| address: 0x69 | |
| update_interval: $sensor_interval | |
| - platform: template | |
| name: Temperature | |
| id: temperature | |
| lambda: |- | |
| return (( id(sen55_temperature).state + id(CO2_temperature).state ) / 2 ) - id(temperature_offset).state; | |
| unit_of_measurement: "°C" | |
| icon: "mdi:thermometer" | |
| device_class: "temperature" | |
| state_class: "measurement" | |
| update_interval: $sensor_interval | |
| accuracy_decimals: 2 | |
| - platform: template | |
| name: Humidity | |
| id: humidity | |
| lambda: |- | |
| return (( id(sen55_humidity).state + id(CO2_humidity).state ) / 2) - id(humidity_offset).state; | |
| unit_of_measurement: "%" | |
| icon: "mdi:water-percent" | |
| device_class: "humidity" | |
| state_class: "measurement" | |
| update_interval: $sensor_interval | |
| accuracy_decimals: 2 | |
| binary_sensor: | |
| - platform: gpio | |
| name: Button A | |
| pin: | |
| number: GPIO0 | |
| ignore_strapping_warning: true | |
| mode: | |
| input: true | |
| inverted: true | |
| on_press: | |
| then: | |
| - component.update: disp | |
| - platform: gpio | |
| pin: | |
| number: GPIO08 | |
| mode: | |
| input: true | |
| pullup: true | |
| inverted: true | |
| name: Button B | |
| - platform: gpio | |
| pin: | |
| number: GPIO46 | |
| ignore_strapping_warning: true | |
| name: Button Hold | |
| - platform: gpio | |
| pin: | |
| number: GPIO42 | |
| name: Button Power | |
| button: | |
| - platform: restart | |
| name: Restart | |
| - platform: template | |
| name: "CO2 Force Manual Calibration" | |
| entity_category: "config" | |
| on_press: | |
| then: | |
| - scd4x.perform_forced_calibration: | |
| value: !lambda 'return id(co2_cal).state;' | |
| - platform: template | |
| name: "SEN55 Force Manual Clean" | |
| entity_category: "config" | |
| on_press: | |
| then: | |
| - sen5x.start_fan_autoclean: sen55 | |
| number: | |
| - platform: template | |
| name: "CO2 Calibration Value" | |
| optimistic: true | |
| min_value: 400 | |
| max_value: 1000 | |
| step: 5 | |
| id: co2_cal | |
| icon: "mdi:molecule-co2" | |
| entity_category: "config" | |
| - platform: template | |
| name: Humidity Offset | |
| id: humidity_offset | |
| restore_value: true | |
| initial_value: 0.0 | |
| min_value: -70.0 | |
| max_value: 70.0 | |
| entity_category: "CONFIG" | |
| unit_of_measurement: "%" | |
| optimistic: true | |
| update_interval: never | |
| step: 0.1 | |
| mode: box | |
| - platform: template | |
| name: Temperature Offset | |
| id: temperature_offset | |
| restore_value: true | |
| initial_value: 0.0 | |
| min_value: -70.0 | |
| max_value: 70.0 | |
| entity_category: "CONFIG" | |
| unit_of_measurement: "°C" | |
| optimistic: true | |
| update_interval: never | |
| step: 0.1 | |
| mode: box | |
| display: | |
| - platform: waveshare_epaper | |
| model: 1.54inv2 | |
| id: disp | |
| cs_pin: GPIO04 | |
| dc_pin: GPIO03 | |
| reset_pin: GPIO02 | |
| busy_pin: | |
| number: GPIO01 | |
| inverted: false | |
| full_update_every: 6 | |
| reset_duration: 2ms | |
| update_interval: 10s | |
| lambda: |- | |
| auto now = id(esptime).now().strftime("%H:%M %d/%m/%y").c_str(); | |
| it.printf(it.get_width()/2, 0, id(f12), TextAlign::TOP_CENTER, "${location} @ %s", now); | |
| it.print(0, 23, id(f24), TextAlign::TOP_LEFT, "PM 1: "); | |
| it.print(0, 48, id(f24), TextAlign::TOP_LEFT, "PM 2.5: "); | |
| it.print(0, 73, id(f24), TextAlign::TOP_LEFT, "PM 4: "); | |
| it.print(0, 98, id(f24), TextAlign::TOP_LEFT, "PM 10: "); | |
| it.print(0, 123, id(f24), TextAlign::TOP_LEFT, "CO2: "); | |
| it.print(0, 148, id(f24), TextAlign::TOP_LEFT, "VOC: "); | |
| it.print(0, 173, id(f24), TextAlign::TOP_LEFT, "NOX: "); | |
| it.printf(it.get_width(), 23, id(f24), TextAlign::TOP_RIGHT, "%.0f", id(PM1_0).state); | |
| it.printf(it.get_width(), 48, id(f24), TextAlign::TOP_RIGHT, "%.0f", id(PM2_5).state); | |
| it.printf(it.get_width(), 73, id(f24), TextAlign::TOP_RIGHT, "%.0f", id(PM4_0).state); | |
| it.printf(it.get_width(), 98, id(f24), TextAlign::TOP_RIGHT, "%.0f", id(PM10_0).state); | |
| it.printf(it.get_width(), 123, id(f24), TextAlign::TOP_RIGHT, "%.0fppm", id(CO2).state); | |
| it.printf(it.get_width(), 148, id(f24), TextAlign::TOP_RIGHT, "%.0f", id(voc).state); | |
| it.printf(it.get_width(), 173, id(f24), TextAlign::TOP_RIGHT, "%.0f", id(nox).state); | |
| font: | |
| - file: | |
| type: gfonts | |
| family: Noto Sans Display | |
| weight: 500 | |
| glyphs: ['&', '@', '!', ',', '.', '"', '%', '(', ')', '+', '-', '_', ':', '°', '0', | |
| '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', | |
| 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', | |
| 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f', | |
| 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', | |
| 'u', 'v', 'w', 'x', 'y', 'z','å', 'ä', 'ö', '/', 'µ', '³', '’'] | |
| id: f16 | |
| size: 16 | |
| - file: | |
| type: gfonts | |
| family: Noto Sans Display | |
| weight: 500 | |
| glyphs: ['&', '@', '!', ',', '.', '"', '%', '(', ')', '+', '-', '_', ':', '°', '0', | |
| '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', | |
| 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', | |
| 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f', | |
| 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', | |
| 'u', 'v', 'w', 'x', 'y', 'z','å', 'ä', 'ö', '/', 'µ', '³', '’'] | |
| id: f18 | |
| size: 18 | |
| - file: | |
| type: gfonts | |
| family: Noto Sans Display | |
| weight: 500 | |
| id: f12 | |
| size: 12 | |
| glyphs: ['&', '@', '!', ',', '.', '"', '%', '(', ')', '+', '-', '_', ':', '°', '0', | |
| '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', | |
| 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', | |
| 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f', | |
| 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', | |
| 'u', 'v', 'w', 'x', 'y', 'z','å', 'ä', 'ö', '/', 'µ', '³', '’'] | |
| - file: | |
| type: gfonts | |
| family: Noto Sans Display | |
| weight: 500 | |
| id: f24 | |
| size: 24 | |
| glyphs: ['&', '@', '!', ',', '.', '"', '%', '(', ')', '+', '-', '_', ':', '°', '0', | |
| '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', | |
| 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', | |
| 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f', | |
| 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', | |
| 'u', 'v', 'w', 'x', 'y', 'z','å', 'ä', 'ö', '/', 'µ', '³', '’'] | |
| - file: | |
| type: gfonts | |
| family: Noto Sans Display | |
| weight: 500 | |
| id: f36 | |
| size: 36 | |
| glyphs: ['&', '@', '!', ',', '.', '"', '%', '(', ')', '+', '-', '_', ':', '°', '0', | |
| '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', | |
| 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', | |
| 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f', | |
| 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', | |
| 'u', 'v', 'w', 'x', 'y', 'z','å', 'ä', 'ö', '/', 'µ', '³', '’'] | |
| - file: | |
| type: gfonts | |
| family: Noto Sans Display | |
| weight: 500 | |
| id: f48 | |
| size: 48 | |
| glyphs: ['&', '@', '!', ',', '.', '"', '%', '(', ')', '+', '-', '_', ':', '°', '0', | |
| '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', | |
| 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', | |
| 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f', | |
| 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', | |
| 'u', 'v', 'w', 'x', 'y', 'z','å', 'ä', 'ö', '/', 'µ', '³', '’'] | |
| - file: | |
| type: gfonts | |
| family: Noto Sans Display | |
| weight: 500 | |
| id: f32 | |
| size: 32 | |
| glyphs: ['&', '@', '!', ',', '.', '"', '%', '(', ')', '+', '-', '_', ':', '°', '0', | |
| '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', | |
| 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', | |
| 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f', | |
| 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', | |
| 'u', 'v', 'w', 'x', 'y', 'z','å', 'ä', 'ö', '/', 'µ', '³', '’'] | |
| - file: | |
| type: gfonts | |
| family: Noto Sans Display | |
| weight: 500 | |
| id: f64 | |
| size: 64 | |
| glyphs: ['&', '@', '!', ',', '.', '"', '%', '(', ')', '+', '-', '_', ':', '°', '0', | |
| '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', | |
| 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', | |
| 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f', | |
| 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', | |
| 'u', 'v', 'w', 'x', 'y', 'z','å', 'ä', 'ö', '/', 'µ', '³', '’'] | |
| - file: | |
| type: gfonts | |
| family: Noto Sans Display | |
| weight: 800 | |
| id: f64b | |
| size: 64 | |
| glyphs: ['&', '@', '!', ',', '.', '"', '%', '(', ')', '+', '-', '_', ':', '°', '0', | |
| '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', | |
| 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', | |
| 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f', | |
| 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', | |
| 'u', 'v', 'w', 'x', 'y', 'z','å', 'ä', 'ö', '/', 'µ', '³', '’'] | |
| - file: | |
| type: gfonts | |
| family: Noto Sans Display | |
| weight: 800 | |
| id: f55b | |
| size: 55 | |
| glyphs: ['&', '@', '!', ',', '.', '"', '%', '(', ')', '+', '-', '_', ':', '°', '0', | |
| '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', | |
| 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', | |
| 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f', | |
| 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', | |
| 'u', 'v', 'w', 'x', 'y', 'z','å', 'ä', 'ö', '/', 'µ', '³', '’'] | |
| - file: | |
| type: gfonts | |
| family: Material Symbols Sharp | |
| weight: 400 | |
| id: font_weather_icons_xsmall | |
| size: 20 | |
| glyphs: | |
| - "\U0000F159" # clear-night | |
| - "\U0000F15B" # cloudy | |
| - "\U0000F172" # partlycloudy | |
| - "\U0000E818" # fog | |
| - "\U0000F67F" # hail | |
| - "\U0000EBDB" # lightning, lightning-rainy | |
| - "\U0000F61F" # pouring | |
| - "\U0000F61E" # rainy | |
| - "\U0000F61C" # snowy | |
| - "\U0000F61D" # snowy-rainy | |
| - "\U0000E81A" # sunny | |
| - "\U0000EFD8" # windy, windy-variant | |
| - "\U0000F7F3" # exceptional | |
| - file: | |
| type: gfonts | |
| family: Material Symbols Sharp | |
| weight: 400 | |
| id: font_weather_icons_small | |
| size: 32 | |
| glyphs: | |
| - "\U0000F159" # clear-night | |
| - "\U0000F15B" # cloudy | |
| - "\U0000F172" # partlycloudy | |
| - "\U0000E818" # fog | |
| - "\U0000F67F" # hail | |
| - "\U0000EBDB" # lightning, lightning-rainy | |
| - "\U0000F61F" # pouring | |
| - "\U0000F61E" # rainy | |
| - "\U0000F61C" # snowy | |
| - "\U0000F61D" # snowy-rainy | |
| - "\U0000E81A" # sunny | |
| - "\U0000EFD8" # windy, windy-variant | |
| - "\U0000F7F3" # exceptional | |
| - file: | |
| type: gfonts | |
| family: Open Sans | |
| weight: 700 | |
| id: font_clock | |
| glyphs: "0123456789:" | |
| size: 70 | |
| - file: | |
| type: gfonts | |
| family: Open Sans | |
| weight: 700 | |
| id: font_clock_big | |
| glyphs: "0123456789:" | |
| size: 100 | |
| - file: "gfonts://Roboto" | |
| id: font_temp | |
| size: 28 | |
| - file: | |
| type: gfonts | |
| family: Open Sans | |
| weight: 500 | |
| id: font_small | |
| size: 30 | |
| glyphs: "!\"%()+=,-_.:°0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz→»" | |
| - file: | |
| type: gfonts | |
| family: Open Sans | |
| weight: 500 | |
| id: font_medium | |
| size: 45 | |
| glyphs: "!\"%()+=,-_.:°0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz→»" | |
| - file: | |
| type: gfonts | |
| family: Open Sans | |
| weight: 300 | |
| id: font_xsmall | |
| size: 16 | |
| glyphs: "!\"%()+=,-_.:°0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz→»" | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment