Skip to content

Commit 86b27b6

Browse files
committed
Improves class interfaces for usability
1 parent 2f6a8e7 commit 86b27b6

File tree

3 files changed

+153
-28
lines changed

3 files changed

+153
-28
lines changed

src/SensorValue/SensorValue.php

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,25 @@ class SensorValue implements \JsonSerializable
1616
const TYPE_ILLUMINANCE = 'illuminance';
1717
const TYPE_POLLUTION_LARGE = 'pollution-large';
1818
const TYPE_POLLUTION_SMALL = 'pollution-small';
19+
const TYPE_DEWPOINT = 'dewpoint';
1920

2021
const UNIT_DEGREE_CELSIUS = '°C';
2122
const UNIT_PERCENT = '%';
23+
const UNIT_PERCENT_RELATIVE = 'rel.%';
2224
const UNIT_HECTOPASCAL = 'hPa';
2325
const UNIT_LUX = 'lx';
2426
const UNIT_MICROWATT_PER_CENTIMETER_SQUARE = 'μW/cm²';
2527
const UNIT_MICROGRAM_PER_METER_CUBE = 'µg/m³';
2628

29+
const SENSOR_HDC1008 = 'HDC1008';
30+
const SENSOR_HDC1080 = 'HDC1080';
31+
const SENSOR_SDS011 = 'SDS 011';
32+
const SENSOR_BME280 = 'BME280';
33+
const SENSOR_BMP280 = 'BMP280';
34+
const SENSOR_TSL45315 = 'TSL45315';
35+
const SENSOR_VEML6070 = 'VEML6070';
36+
const SENSOR_UNKOWN = 'unknown';
37+
2738
const KNOWN_VALUE_TYPES = [
2839
self::TYPE_TEMPERATURE,
2940
self::TYPE_HUMIDITY,
@@ -32,26 +43,40 @@ class SensorValue implements \JsonSerializable
3243
self::TYPE_ILLUMINANCE,
3344
self::TYPE_POLLUTION_LARGE,
3445
self::TYPE_POLLUTION_SMALL,
46+
self::TYPE_DEWPOINT,
47+
];
48+
49+
const KNOWN_SENSORS = [
50+
self::SENSOR_HDC1008,
51+
self::SENSOR_HDC1080,
52+
self::SENSOR_SDS011,
53+
self::SENSOR_BME280,
54+
self::SENSOR_BMP280,
55+
self::SENSOR_TSL45315,
56+
self::SENSOR_VEML6070,
3557
];
3658

3759
const KNOWN_SENSOR_UNITS = [
38-
'HDC1080' => [self::UNIT_DEGREE_CELSIUS, self::UNIT_PERCENT],
39-
'HDC1008' => [self::UNIT_DEGREE_CELSIUS, self::UNIT_PERCENT],
40-
'SDS 011' => [self::UNIT_MICROGRAM_PER_METER_CUBE],
41-
'BME280' => [self::UNIT_HECTOPASCAL, self::UNIT_DEGREE_CELSIUS, self::UNIT_PERCENT],
42-
'BMP280' => [self::UNIT_HECTOPASCAL],
43-
'TSL45315' => [self::UNIT_LUX],
44-
'VEML6070' => [self::UNIT_MICROWATT_PER_CENTIMETER_SQUARE],
60+
self::SENSOR_HDC1080 => [self::UNIT_DEGREE_CELSIUS, self::UNIT_PERCENT],
61+
self::SENSOR_HDC1008 => [self::UNIT_DEGREE_CELSIUS, self::UNIT_PERCENT],
62+
self::SENSOR_SDS011 => [self::UNIT_MICROGRAM_PER_METER_CUBE],
63+
self::SENSOR_BME280 => [self::UNIT_HECTOPASCAL, self::UNIT_DEGREE_CELSIUS, self::UNIT_PERCENT, self::UNIT_PERCENT_RELATIVE],
64+
self::SENSOR_BMP280 => [self::UNIT_HECTOPASCAL],
65+
self::SENSOR_TSL45315 => [self::UNIT_LUX],
66+
self::SENSOR_VEML6070 => [self::UNIT_MICROWATT_PER_CENTIMETER_SQUARE],
4567
];
4668

4769
const KNOWN_VALUE_TYPE_TITLES = [
4870
'Temperatur' => self::TYPE_TEMPERATURE,
71+
'Temperature' => self::TYPE_TEMPERATURE,
4972
'Beleuchtungsstärke' => self::TYPE_ILLUMINANCE,
5073
'UV-Intensität' => self::TYPE_UV_INTENSITY,
5174
'PM10' => self::TYPE_POLLUTION_LARGE,
5275
'PM2.5' => self::TYPE_POLLUTION_SMALL,
5376
'Luftdruck' => self::TYPE_AIR_PRESSURE,
5477
'rel. Luftfeuchte' => self::TYPE_HUMIDITY,
78+
'Luftfeuchte' => self::TYPE_HUMIDITY,
79+
'Taupunkt' => self::TYPE_DEWPOINT,
5580
];
5681

5782
const VALUE_TYPE_UNITS = [
@@ -62,6 +87,7 @@ class SensorValue implements \JsonSerializable
6287
self::TYPE_ILLUMINANCE => self::UNIT_LUX,
6388
self::TYPE_POLLUTION_LARGE => self::UNIT_MICROGRAM_PER_METER_CUBE,
6489
self::TYPE_POLLUTION_SMALL => self::UNIT_MICROGRAM_PER_METER_CUBE,
90+
self::TYPE_DEWPOINT => self::UNIT_DEGREE_CELSIUS,
6591
];
6692

6793
/** @var string */
@@ -93,21 +119,11 @@ class SensorValue implements \JsonSerializable
93119
*/
94120
public function __construct(string $sensorType, string $sensorId, string $valueType)
95121
{
96-
if (!array_key_exists($sensorType, self::KNOWN_SENSOR_UNITS)) {
97-
throw new OpensensemapApiClientException(sprintf(
98-
'Unknown sensor type %s',
99-
$sensorType
100-
));
101-
}
102-
103-
if (!in_array($valueType, self::KNOWN_VALUE_TYPES)) {
104-
throw new OpensensemapApiClientException(sprintf(
105-
'Unknown value type %s',
106-
$valueType
107-
));
122+
if (!in_array($sensorType, self::KNOWN_SENSORS)) {
123+
$sensorType = self::SENSOR_UNKOWN;
108124
}
109125

110-
if (!in_array(self::VALUE_TYPE_UNITS[$valueType], self::KNOWN_SENSOR_UNITS[$sensorType])) {
126+
if ($sensorType !== self::SENSOR_UNKOWN && !in_array(self::VALUE_TYPE_UNITS[$valueType], self::KNOWN_SENSOR_UNITS[$sensorType])) {
111127
throw new OpensensemapApiClientException(sprintf(
112128
'Unknown value type %s for sensor %s',
113129
$valueType,
@@ -143,7 +159,7 @@ public function getSensorId(): string
143159
*/
144160
public function setUnit(string $unit)
145161
{
146-
if (!in_array($unit, self::KNOWN_SENSOR_UNITS[$this->sensorType])) {
162+
if ($this->sensorType !== self::SENSOR_UNKOWN && !in_array($unit, self::KNOWN_SENSOR_UNITS[$this->sensorType])) {
147163
throw new OpensensemapApiClientException(sprintf(
148164
'Unit %s not known for sensor %s',
149165
$unit,
@@ -201,6 +217,18 @@ public function getMeasurementTime(): \DateTimeImmutable
201217
return $this->measurementTime;
202218
}
203219

220+
/**
221+
* @return string
222+
*/
223+
public function __toString()
224+
{
225+
return sprintf(
226+
'%s %s',
227+
$this->getValue() ?? '--',
228+
$this->getUnit() ?? 'XX'
229+
);
230+
}
231+
204232
/**
205233
* @return array
206234
*/

src/SensorValue/SensorValueCollection.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,42 @@ public function getSensorValues(): array
2828
return $this->sensorValues;
2929
}
3030

31+
/**
32+
* Looks for the first sensor of the given type and returns it
33+
*
34+
* @param string $sensorType
35+
*
36+
* @return SensorValue|null
37+
*/
38+
public function getValueBySensor(string $sensorType): ?SensorValue
39+
{
40+
foreach ($this->sensorValues as $sensorValue) {
41+
if ($sensorType === $sensorValue->getSensorType()) {
42+
return $sensorValue;
43+
}
44+
}
45+
46+
return null;
47+
}
48+
49+
/**
50+
* Looks for the first value of the given type and returns it
51+
*
52+
* @param string $valueType
53+
*
54+
* @return SensorValue|null
55+
*/
56+
public function getValueByType(string $valueType): ?SensorValue
57+
{
58+
foreach ($this->sensorValues as $sensorValue) {
59+
if ($valueType === $sensorValue->getValueType()) {
60+
return $sensorValue;
61+
}
62+
}
63+
64+
return null;
65+
}
66+
3167
/**
3268
* @return array
3369
*/

tests/OpensensemapApiClientTest.php

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ public function testRequestReturnsProperlyMappedSensorValuesSample1()
3131

3232
$sensorData = $client->getSenseBoxData('123456789123456');
3333
$this->assertInstanceOf(SensorValueCollection::class, $sensorData);
34-
$this->assertCount(5, $sensorData->getSensorValues());
34+
$this->assertCount(5, $sensorData);
3535

3636
/** @var SensorValue $sensorValue */
37-
foreach ($sensorData->getSensorValues() as $sensorValue) {
37+
foreach ($sensorData as $sensorValue) {
3838
$this->assertInstanceOf(SensorValue::class, $sensorValue);
3939
$this->assertNotNull($sensorValue->getValue());
4040
$this->assertNotNull($sensorValue->getUnit());
@@ -54,28 +54,89 @@ public function testRequestReturnsProperlyMappedSensorValuesSample2()
5454

5555
$sensorData = $client->getSenseBoxData('123456789123456');
5656
$this->assertInstanceOf(SensorValueCollection::class, $sensorData);
57-
$this->assertCount(5, $sensorData->getSensorValues());
57+
$this->assertCount(5, $sensorData);
5858

5959
/** @var SensorValue $sensorValue */
60-
foreach ($sensorData->getSensorValues() as $sensorValue) {
60+
foreach ($sensorData as $sensorValue) {
6161
$this->assertInstanceOf(SensorValue::class, $sensorValue);
6262
$this->assertNotNull($sensorValue->getValue());
6363
$this->assertNotNull($sensorValue->getUnit());
6464
$this->assertInstanceOf(\DateTimeImmutable::class, $sensorValue->getMeasurementTime());
6565
}
6666
}
6767

68-
public function testInvalidSensorThrowsException()
68+
public function testUnknownSensorGetsMappedAsUnkown()
6969
{
7070
$mock = new MockHandler([
71-
new Response(200, [], '{"_id":"123456789123456","createdAt":"2019-07-31T19:52:40.731Z","updatedAt":"2019-08-01T07:33:39.097Z","name":"Somewhere","currentLocation":{"timestamp":"2019-07-31T19:52:40.721Z","coordinates":[37.234332396,-115.80666344],"type":"Point"},"exposure":"indoor","sensors":[{"title":"Temperatur","unit":"°C","sensorType":"HDC1080","icon":"osem-thermometer","_id":"123456789123456","lastMeasurement":{"value":"24.90","createdAt":"2019-08-01T07:33:39.093Z"}},{"title":"rel. Luftfeuchte","unit":"%","sensorType":"HDC1080","icon":"osem-humidity","_id":"123456789123456","lastMeasurement":{"value":"49.58","createdAt":"2019-08-01T07:33:39.093Z"}},{"title":"Luftdruck","unit":"hPa","sensorType":"UNKOWNSENSOR","icon":"osem-barometer","_id":"123456789123456","lastMeasurement":{"value":"1006.33","createdAt":"2019-08-01T07:33:39.093Z"}},{"title":"Beleuchtungsstärke","unit":"lx","sensorType":"TSL45315","icon":"osem-brightness","_id":"123456789123456","lastMeasurement":{"value":"116.00","createdAt":"2019-08-01T07:33:39.093Z"}},{"title":"UV-Intensität","unit":"μW/cm²","sensorType":"VEML6070","icon":"osem-brightness","_id":"123456789123456","lastMeasurement":{"value":"5.62","createdAt":"2019-08-01T07:33:39.093Z"}}],"model":"homeV2Wifi","lastMeasurementAt":"2019-08-01T07:33:39.093Z","loc":[{"geometry":{"timestamp":"2019-07-31T19:52:40.721Z","coordinates":[37.234332396,-115.80666344],"type":"Point"},"type":"Feature"}]}'),
71+
new Response(200, [], '{"_id":"123456789123456df","createdAt":"2019-07-10T07:36:22.817Z","updatedAt":"2019-08-02T06:13:10.358Z","name":"SomeWhere","currentLocation":{"type":"Point","coordinates":[37.234332396,-115.80666344],"timestamp":"2019-07-13T10:10:29.245Z"},"exposure":"outdoor","sensors":[{"icon":"osem-thermometer","title":"Temperature","unit":"°C","sensorType":"BME280","_id":"123456789123456e2","lastMeasurement":{"value":"17","createdAt":"2019-08-02T06:13:10.046Z"}},{"_id":"123456789123456e1","title":"Luftfeuchte","unit":"rel.%","sensorType":"BME280","icon":"osem-humidity","lastMeasurement":{"value":"71.7","createdAt":"2019-08-02T06:13:10.147Z"}},{"_id":"123456789123456e0","title":"Luftdruck","unit":"hPa","sensorType":"BME280","icon":"osem-dashboard","lastMeasurement":{"value":"983.9","createdAt":"2019-08-02T06:13:10.243Z"}},{"_id":"5d2795f130bde6001a1d2b7a","title":"Taupunkt","unit":"°C","sensorType":"Calc from BME","icon":"osem-moisture","lastMeasurement":{"value":"11.9","createdAt":"2019-08-02T06:13:10.353Z"}}],"model":"custom","description":"First Sensorbox DIY with ESp8266 and BME280.","lastMeasurementAt":"2019-08-02T06:13:10.353Z","loc":[{"geometry":{"type":"Point","coordinates":[37.234332396,-115.80666344],"timestamp":"2019-07-13T10:10:29.245Z"},"type":"Feature"}]}'),
7272
]);
7373

7474
$handler = HandlerStack::create($mock);
7575
$httpClient = new Client(['handler' => $handler]);
7676
$client = new OpensensemapApiClient($httpClient);
7777

78-
$this->expectException(OpensensemapApiClientException::class);
7978
$sensorData = $client->getSenseBoxData('123456789123456');
79+
$this->assertCount(4, $sensorData);
80+
$unknownSensorsValue = $sensorData->getValueBySensor(SensorValue::SENSOR_UNKOWN);
81+
$this->assertInstanceOf(SensorValue::class, $unknownSensorsValue);
82+
}
83+
84+
public function testValuesCanBeAccessedByType()
85+
{
86+
$mock = new MockHandler([
87+
new Response(200, [], '{"_id":"123456789123456df","createdAt":"2019-07-10T07:36:22.817Z","updatedAt":"2019-08-02T06:13:10.358Z","name":"SomeWhere","currentLocation":{"type":"Point","coordinates":[37.234332396,-115.80666344],"timestamp":"2019-07-13T10:10:29.245Z"},"exposure":"outdoor","sensors":[{"icon":"osem-thermometer","title":"Temperature","unit":"°C","sensorType":"BME280","_id":"123456789123456e2","lastMeasurement":{"value":"17","createdAt":"2019-08-02T06:13:10.046Z"}},{"_id":"123456789123456e1","title":"Luftfeuchte","unit":"rel.%","sensorType":"BME280","icon":"osem-humidity","lastMeasurement":{"value":"71.7","createdAt":"2019-08-02T06:13:10.147Z"}},{"_id":"123456789123456e0","title":"Luftdruck","unit":"hPa","sensorType":"BME280","icon":"osem-dashboard","lastMeasurement":{"value":"983.9","createdAt":"2019-08-02T06:13:10.243Z"}},{"_id":"5d2795f130bde6001a1d2b7a","title":"Taupunkt","unit":"°C","sensorType":"Calc from BME","icon":"osem-moisture","lastMeasurement":{"value":"11.9","createdAt":"2019-08-02T06:13:10.353Z"}}],"model":"custom","description":"First Sensorbox DIY with ESp8266 and BME280.","lastMeasurementAt":"2019-08-02T06:13:10.353Z","loc":[{"geometry":{"type":"Point","coordinates":[37.234332396,-115.80666344],"timestamp":"2019-07-13T10:10:29.245Z"},"type":"Feature"}]}'),
88+
]);
89+
90+
$handler = HandlerStack::create($mock);
91+
$httpClient = new Client(['handler' => $handler]);
92+
$client = new OpensensemapApiClient($httpClient);
93+
94+
$sensorData = $client->getSenseBoxData('123456789123456');
95+
96+
$dewpoint = $sensorData->getValueBySensor(SensorValue::SENSOR_UNKOWN);
97+
$this->assertInstanceOf(SensorValue::class, $dewpoint);
98+
$this->assertEquals(SensorValue::TYPE_DEWPOINT, $dewpoint->getValueType());
99+
$this->assertEquals(11.9, $dewpoint->getValue());
100+
unset($dewpoint);
101+
102+
$dewpoint2 = $sensorData->getValueByType(SensorValue::TYPE_DEWPOINT);
103+
$this->assertInstanceOf(SensorValue::class, $dewpoint2);
104+
$this->assertEquals(SensorValue::SENSOR_UNKOWN, $dewpoint2->getSensorType());
105+
$this->assertEquals(11.9, $dewpoint2->getValue());
106+
unset($dewpoint2);
107+
108+
$temperature = $sensorData->getValueByType(SensorValue::TYPE_TEMPERATURE);
109+
$this->assertInstanceOf(SensorValue::class, $temperature);
110+
$this->assertEquals(SensorValue::SENSOR_BME280, $temperature->getSensorType());
111+
$this->assertEquals(17, $temperature->getValue());
112+
}
113+
114+
public function testValuesAreIterable()
115+
{
116+
$mock = new MockHandler([
117+
new Response(200, [], '{"_id":"123456789123456df","createdAt":"2019-07-10T07:36:22.817Z","updatedAt":"2019-08-02T06:13:10.358Z","name":"SomeWhere","currentLocation":{"type":"Point","coordinates":[37.234332396,-115.80666344],"timestamp":"2019-07-13T10:10:29.245Z"},"exposure":"outdoor","sensors":[{"icon":"osem-thermometer","title":"Temperature","unit":"°C","sensorType":"BME280","_id":"123456789123456e2","lastMeasurement":{"value":"17","createdAt":"2019-08-02T06:13:10.046Z"}},{"_id":"123456789123456e1","title":"Luftfeuchte","unit":"rel.%","sensorType":"BME280","icon":"osem-humidity","lastMeasurement":{"value":"71.7","createdAt":"2019-08-02T06:13:10.147Z"}},{"_id":"123456789123456e0","title":"Luftdruck","unit":"hPa","sensorType":"BME280","icon":"osem-dashboard","lastMeasurement":{"value":"983.9","createdAt":"2019-08-02T06:13:10.243Z"}},{"_id":"5d2795f130bde6001a1d2b7a","title":"Taupunkt","unit":"°C","sensorType":"Calc from BME","icon":"osem-moisture","lastMeasurement":{"value":"11.9","createdAt":"2019-08-02T06:13:10.353Z"}}],"model":"custom","description":"First Sensorbox DIY with ESp8266 and BME280.","lastMeasurementAt":"2019-08-02T06:13:10.353Z","loc":[{"geometry":{"type":"Point","coordinates":[37.234332396,-115.80666344],"timestamp":"2019-07-13T10:10:29.245Z"},"type":"Feature"}]}'),
118+
]);
119+
120+
$handler = HandlerStack::create($mock);
121+
$httpClient = new Client(['handler' => $handler]);
122+
$client = new OpensensemapApiClient($httpClient);
123+
124+
$sensorData = $client->getSenseBoxData('123456789123456');
125+
$this->assertIsIterable($sensorData);
126+
}
127+
128+
public function testValuesCanBeUsedAsString()
129+
{
130+
$mock = new MockHandler([
131+
new Response(200, [], '{"_id":"123456789123456df","createdAt":"2019-07-10T07:36:22.817Z","updatedAt":"2019-08-02T06:13:10.358Z","name":"SomeWhere","currentLocation":{"type":"Point","coordinates":[37.234332396,-115.80666344],"timestamp":"2019-07-13T10:10:29.245Z"},"exposure":"outdoor","sensors":[{"icon":"osem-thermometer","title":"Temperature","unit":"°C","sensorType":"BME280","_id":"123456789123456e2","lastMeasurement":{"value":"17","createdAt":"2019-08-02T06:13:10.046Z"}},{"_id":"123456789123456e1","title":"Luftfeuchte","unit":"rel.%","sensorType":"BME280","icon":"osem-humidity","lastMeasurement":{"value":"71.7","createdAt":"2019-08-02T06:13:10.147Z"}},{"_id":"123456789123456e0","title":"Luftdruck","unit":"hPa","sensorType":"BME280","icon":"osem-dashboard","lastMeasurement":{"value":"983.9","createdAt":"2019-08-02T06:13:10.243Z"}},{"_id":"5d2795f130bde6001a1d2b7a","title":"Taupunkt","unit":"°C","sensorType":"Calc from BME","icon":"osem-moisture","lastMeasurement":{"value":"11.9","createdAt":"2019-08-02T06:13:10.353Z"}}],"model":"custom","description":"First Sensorbox DIY with ESp8266 and BME280.","lastMeasurementAt":"2019-08-02T06:13:10.353Z","loc":[{"geometry":{"type":"Point","coordinates":[37.234332396,-115.80666344],"timestamp":"2019-07-13T10:10:29.245Z"},"type":"Feature"}]}'),
132+
]);
133+
134+
$handler = HandlerStack::create($mock);
135+
$httpClient = new Client(['handler' => $handler]);
136+
$client = new OpensensemapApiClient($httpClient);
137+
138+
$sensorData = $client->getSenseBoxData('123456789123456');
139+
$temperature = $sensorData->getValueByType(SensorValue::TYPE_TEMPERATURE);
140+
$this->assertEquals('17 °C', (string)$temperature);
80141
}
81142
}

0 commit comments

Comments
 (0)