Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for the cgllc.airmonitor.b1 #562

Merged
merged 16 commits into from
Oct 20, 2019
48 changes: 39 additions & 9 deletions miio/airqualitymonitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,19 @@
"sensor_state",
]

AVAILABLE_PROPERTIES_B1 = [
"co2e",
fwestenberg marked this conversation as resolved.
Show resolved Hide resolved
"humidity",
fwestenberg marked this conversation as resolved.
Show resolved Hide resolved
"pm25",
fwestenberg marked this conversation as resolved.
Show resolved Hide resolved
"temperature",
fwestenberg marked this conversation as resolved.
Show resolved Hide resolved
"tvoc"
]

AVAILABLE_PROPERTIES_S1 = ["battery", "co2", "humidity", "pm25", "temperature", "tvoc"]

AVAILABLE_PROPERTIES = {
MODEL_AIRQUALITYMONITOR_V1: AVAILABLE_PROPERTIES_COMMON,
MODEL_AIRQUALITYMONITOR_B1: AVAILABLE_PROPERTIES_COMMON,
MODEL_AIRQUALITYMONITOR_B1: AVAILABLE_PROPERTIES_B1,
MODEL_AIRQUALITYMONITOR_S1: AVAILABLE_PROPERTIES_S1,
}

Expand All @@ -49,7 +57,8 @@ def __init__(self, data):

Response of a Xiaomi Air Quality Monitor (cgllc.airmonitor.b1):

unknown.
{'co2e': 1466, 'humidity': 59.79999923706055, 'pm25': 2, 'temperature': 19.799999237060547,
fwestenberg marked this conversation as resolved.
Show resolved Hide resolved
'temperature_unit': 'c', 'tvoc': 1.3948699235916138, 'tvoc_unit': 'mg_m3'}

Response of a Xiaomi Air Quality Monitor (cgllc.airmonitor.s1):

Expand All @@ -63,6 +72,7 @@ def power(self) -> Optional[str]:
"""Current power state."""
if "power" in self.data and self.data["power"] is not None:
return self.data["power"]

return None

@property
Expand All @@ -75,88 +85,103 @@ def usb_power(self) -> Optional[bool]:
"""Return True if the device's usb is on."""
if "usb_state" in self.data and self.data["usb_state"] is not None:
return self.data["usb_state"] == "on"

return None

@property
def aqi(self) -> Optional[int]:
"""Air quality index value. (0...600)."""
if "aqi" in self.data and self.data["aqi"] is not None:
return self.data["aqi"]

return None

@property
def battery(self) -> int:
def battery(self) -> Optional[int]:
"""Current battery level (0...100)."""
return self.data["battery"]
if "battery" in self.data and self.data["battery"] is not None:
return self.data["battery"]

return None
fwestenberg marked this conversation as resolved.
Show resolved Hide resolved

@property
def display_clock(self) -> Optional[bool]:
"""Display a clock instead the AQI."""
if "time_state" in self.data and self.data["time_state"] is not None:
return self.data["time_state"] == "on"

return None

@property
def night_mode(self) -> Optional[bool]:
"""Return True if the night mode is on."""
if "night_state" in self.data and self.data["night_state"] is not None:
return self.data["night_state"] == "on"

return None

@property
def night_time_begin(self) -> Optional[str]:
"""Return the begin of the night time."""
if "night_beg_time" in self.data and self.data["night_beg_time"] is not None:
return self.data["night_beg_time"]

return None

@property
def night_time_end(self) -> Optional[str]:
"""Return the end of the night time."""
if "night_end_time" in self.data and self.data["night_end_time"] is not None:
return self.data["night_end_time"]

return None

@property
def sensor_state(self) -> Optional[str]:
"""Sensor state."""
if "sensor_state" in self.data and self.data["sensor_state"] is not None:
return self.data["sensor_state"]

return None

@property
def co2(self) -> Optional[int]:
"""Return co2 value (400...9999ppm)."""
if "co2" in self.data and self.data["co2"] is not None:
return self.data["co2"]

return None

@property
def humidity(self) -> Optional[float]:
"""Return humidity value (0...100%)."""
if "humidity" in self.data and self.data["humidity"] is not None:
return self.data["humidity"]

return None

@property
def pm25(self) -> Optional[float]:
"""Return pm2.5 value (0...999μg/m³)."""
if "pm25" in self.data and self.data["pm25"] is not None:
return self.data["pm25"]

return None

@property
def temperature(self) -> Optional[float]:
"""Return temperature value (-10...50°C)."""
if "temperature" in self.data and self.data["temperature"] is not None:
return self.data["temperature"]

return None

@property
def tvoc(self) -> Optional[int]:
"""Return tvoc value."""
if "tvoc" in self.data and self.data["tvoc"] is not None:
return self.data["tvoc"]

fwestenberg marked this conversation as resolved.
Show resolved Hide resolved
return None

def __repr__(self) -> str:
Expand Down Expand Up @@ -208,9 +233,7 @@ def __init__(
self.model = model
else:
self.model = MODEL_AIRQUALITYMONITOR_V1
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When a model is provided, but not in available_properties fallback is still there.

_LOGGER.error(
"Device model %s unsupported. Falling back to %s.", model, self.model
)
_LOGGER.error("Device model %s unsupported. Falling back to %s.", model, self.model)

@command(
default_output=format_output(
Expand All @@ -230,9 +253,16 @@ def __init__(
def status(self) -> AirQualityMonitorStatus:
"""Return device status."""

if info.model is None:
fwestenberg marked this conversation as resolved.
Show resolved Hide resolved
info = self.info()
self.model = info.model

properties = AVAILABLE_PROPERTIES[self.model]

values = self.send("get_prop", properties)
if self.model == MODEL_AIRQUALITYMONITOR_B1:
values = self.send("get_air_data")
else:
values = self.send("get_prop", properties)

properties_count = len(properties)
values_count = len(values)
Expand All @@ -244,7 +274,7 @@ def status(self) -> AirQualityMonitorStatus:
values_count,
)

if self.model == MODEL_AIRQUALITYMONITOR_S1:
if self.model == MODEL_AIRQUALITYMONITOR_S1 or self.model == MODEL_AIRQUALITYMONITOR_B1:
fwestenberg marked this conversation as resolved.
Show resolved Hide resolved
return AirQualityMonitorStatus(defaultdict(lambda: None, values))
else:
return AirQualityMonitorStatus(
Expand Down