Compare commits
73 Commits
a095936f3f
...
master
Author | SHA1 | Date | |
---|---|---|---|
565dac1946 | |||
a8499a27b2 | |||
bedd9c3011 | |||
fd7e0df860 | |||
86a830897f | |||
058e57e1f5 | |||
a74469bb2e | |||
f7a842a7c1 | |||
c92ed75f06 | |||
81b1aeed03 | |||
a08c2a8c02 | |||
0627436adf | |||
15b48e375b | |||
f48231f3b5 | |||
8bad9e2524 | |||
eee1c30cac | |||
eba065dd2d | |||
4a416fa710 | |||
b2845eb479 | |||
98c7993f12 | |||
2ac96fe166 | |||
68a907ef3c | |||
fb57d2fc87 | |||
d6bccabea6 | |||
4f0dc7082a | |||
a03e12dfa7 | |||
1f7df559b1 | |||
d75a7d26a6 | |||
e4c1ab1ac2 | |||
efd9fc8bfe | |||
9aebae647a | |||
3300ca2d8e | |||
0ba3b855d0 | |||
4f6597d92f | |||
985e7e20e5 | |||
426684e9da | |||
7fe3829544 | |||
206691257d | |||
aca7e16ed0 | |||
556f8564c4 | |||
8114d765f0 | |||
d529f695a3 | |||
c0b5adecca | |||
5c94e56847 | |||
fd7e438c62 | |||
64cb43dec8 | |||
e224044de3 | |||
450ff085d2 | |||
f3d7b16aa9 | |||
e62b9a8b91 | |||
9555fd37dc | |||
b3b9fd7086 | |||
cec8d27a4a | |||
40f0ae215a | |||
90403f990b | |||
1eb8e2134f | |||
6c32edc9a9 | |||
7221213ac4 | |||
28b76d0508 | |||
647e6711b8 | |||
7d5d7da2e8 | |||
565df10fe0 | |||
21fc3436ee | |||
91d9ff2a43 | |||
1600417026 | |||
decf2ad244 | |||
6695f9eb6b | |||
3768589de2 | |||
713a693cef | |||
d680735be3 | |||
6cdf340c5b | |||
4157ee2e65 | |||
e1840a37aa |
369
README.md
@@ -10,86 +10,187 @@ interfaces with wake word detection, as well as other sensor detection options
|
||||
as you want them.
|
||||
|
||||
Assist feedback is provided by a pair of common-cathode RGB LED. No speakers
|
||||
or annoying TTS feedback here! With an optional 3D Printed case and a clear
|
||||
diffuser cover, the LEDs can be turned into a sleek light bar on the bottom
|
||||
or annoying TTS feedback here! With [an optional 3D Printed case and a clear
|
||||
diffuser cover](/case), the LEDs can be turned into a sleek light bar on the bottom
|
||||
of the unit for quick and easy confirmation of voice actions, or just use
|
||||
it bare if you like the "PCB on a wall" aesthetic.
|
||||
|
||||
To Use:
|
||||
|
||||
* Install the ESPHome configuration `supersensor.yaml` to a compatible ESP32 devkit (below).
|
||||
* Install the ESP32 and sensors into the custom PCB (if desired).
|
||||
* [Optional] 3D Print the custom case.
|
||||
* Install the ESP32 and sensors into the custom PCB.
|
||||
* Power up the SuperSensor, connect to the WiFi AP, and connect it to your network.
|
||||
* Install the SuperSensor somewhere that makes sense.
|
||||
* Add/adopt the SuperSensor to HomeAssistant using the automatic name.
|
||||
* Tune the SuperSensor values to your needs.
|
||||
|
||||
Note: Once programmed, the output LED will flash continuously until connected
|
||||
to HomeAssistant, and a bit longer to establish if the wake word
|
||||
functionality is enabled. This is by design, so you know if your sensors
|
||||
are connected or not. If you do not want this, comment out the
|
||||
`light.turn_on` block starting on line 38 of the ESPHome configuration
|
||||
to disable this functionality.
|
||||
For more details, please [see my first blog post on the original SuperSensor project](https://www.boniface.me/posts/the-supersensor/)
|
||||
and [my update post on version 2.0](https://www.boniface.me/posts/the-supersensor-2.0).
|
||||
|
||||
For more details, please [see my first blog post on the SuperSensor project](https://www.boniface.me/the-supersensor/)
|
||||
and [my update post on version 2.0](https://www.boniface.me/the-supersensor-2.0).
|
||||
|
||||
**NOTE: For those with v1.x hardware, see [the branch for that code instead](https://github.com/joshuaboniface/supersensor/tree/v1.x).**
|
||||
**NOTE: For those with v1.x hardware, see [the repository for that code instead](https://github.com/joshuaboniface/supersensor).**
|
||||
|
||||
## Major Changes from 1.x
|
||||
|
||||
1. Replaced the Bosch BME680 with the Sensirion SHT45 and Sensirion SGP30.
|
||||
1. Replaced the Bosch BME680 with the Sensirion SHT45 and Sensirion SGP41.
|
||||
|
||||
The BME680 proved to be woefully unreliable in my testing. Temperature and humidity were wildly off of what other thermometers/hydrometers
|
||||
would report, including a known issue with self-heating rending the temperature anywhere from 2 to 5(!) degrees Celsius above the actual
|
||||
temperature.
|
||||
The BME680 proved to be woefully unreliable in my testing. Temperature was fairly accurate (internal heating and offset notwithstanding),
|
||||
but humidity was wildly off of what other thermometers/hydrometers would report. In addition, the AQ functionality of the sensor was a
|
||||
source of much frustration and I was never able to get it to work reliably, either with the official BSEC library or with my own attempts
|
||||
at self-configuration.
|
||||
|
||||
In addition, the AQ functionality of the sensor was a source of much frustration and I was never able to get it to work reliably, either
|
||||
with the official BSEC library or with my own attempts at self-configuration.
|
||||
|
||||
Thus, this sensor has been replaced with two Sensirion sensors which in my experience so far have been much more reliable and consistent,
|
||||
and the cost difference is negligible.
|
||||
Thus, this sensor has been replaced with two Sensirion sensors which in my experience so far have been much more reliable and consistent.
|
||||
There is a slight cost increase due to these sensors, but not signfigant enough to outweigh the benefit of reliable monitoring they confer.
|
||||
|
||||
2. Replaced the SR602 PIR sensor with the AM312 PIR sensor.
|
||||
|
||||
The SR602 was, in my experience, prone to constant false misfirings even in completely empty rooms. In addition its orientation requirements
|
||||
are awkward (pins on the left or right side). While it's possible I just had a bad batch, this soured me significantly to these sensors,
|
||||
especially after reading many other similar reports around the internet.
|
||||
The SR602 was, in my experience, prone to constant false misfirings and hard to enclose due to its shape. In addition its orientation is
|
||||
awkward (pins on the left or right side) which made building around it difficult. Thus, this sensor has been replaced with the nicer,
|
||||
more straight AM312 PIR design. This does add vertical height to the sensor but I consider this a good tradeoff, and think it looks neat.
|
||||
|
||||
Thus, this sensor has been replaced with the more reliable AM312. While the form factor fo the AM312 leaves a bit to be desired (sticking
|
||||
up by about 1cm more from the board), in the end I found this to be more of a positive than a negative for resposiveness and apperance.
|
||||
Note that like all cheap PIRs, the AM312 is prone to misfiring if exposed. For this reason, [the case](/case) is recommended for any serious
|
||||
PIR use-cases.
|
||||
|
||||
3. Completely redesigned the custom PCB around the above sensor changes, which is now more compact in a 50x55mm almost-square configuration.
|
||||
|
||||
4. Significantly cleaned up the ESPHome configuration, to support the above sensors and remove a lot of cruft that was caused by the BME680.
|
||||
This includes a new set of custom AQ calculations based on the SGP30 and SHT45 sensors that, while not necessarily following the full EPA
|
||||
IAQI spec, should still give a reasonable view of the air quality conditions of an interior room and not deviate wildly and nonsensically
|
||||
like the BME680 did. Details of the calculation are provided below.
|
||||
|
||||
## Parts List
|
||||
|
||||
| Qty | Component | Cost (2025/05 CAD, ex. shipping) | Links |
|
||||
|-------|--------------------|----------------------------------|-------|
|
||||
| 1 | GY-SGP30 | $5.73 | [AliExpress](https://www.aliexpress.com/item/1005008473372972.html) |
|
||||
| 1 | GY-SGP41 | $11.08 | [AliExpress](https://www.aliexpress.com/item/1005006746827606.html) |
|
||||
| 1 | GY-SHT45 | $5.67 | [AliExpress](https://www.aliexpress.com/item/1005008175340220.html)* |
|
||||
| 1 | SR602 | $0.81 | [AliExpress](https://www.aliexpress.com/item/1005001572550300.html) |
|
||||
| 1 | AM312 | $1.97 | [AliExpress](https://www.aliexpress.com/item/1005008067324301.html) |
|
||||
| 1 | TSL2591 | $4.59 | [AliExpress](https://www.aliexpress.com/item/1005008619462097.html) |
|
||||
| 1 | HL-LD2510C | $4.79 | [AliExpress](https://www.aliexpress.com/item/1005006000579211.html)* |
|
||||
| 1 | INMP441 | $2.93 | [AliExpress](https://www.aliexpress.com/item/1005002902615623.html) |
|
||||
| 1 | ESP32 HW-395 | $6.67 | [AliExpress](https://www.aliexpress.com/item/1005006019875837.html)* |
|
||||
| 2 | RBG LED | $0.09 ($9.12/100) | [Amazon](https://www.amazon.ca/dp/B09Y8M2PKS) |
|
||||
| 1 | 470Ω resistor | $0.08 ($7.99/100) | [Amazon](https://www.amazon.ca/dp/B08MKQX2XT) |
|
||||
| 1 | Female pin header† | $1.59 ($15.99/10) | [Amazon](https://www.amazon.ca/dp/B08CMNRXJ1) |
|
||||
| 2 | Female pin header† | $1.59 ($15.99/10) | [Amazon](https://www.amazon.ca/dp/B08CMNRXJ1) |
|
||||
| 1 | Custom PCB (JLC) | $0.69 ($6.89/10) | [GitHub](https://github.com/joshuaboniface/supersensor) |
|
||||
| 1 | 3D Printed case | $?.??‡ | [GitHub](https://github.com/joshuaboniface/supersensor) |
|
||||
| **TOTAL** | | **$33.64** | |
|
||||
| **TOTAL** | | **$41.74** | |
|
||||
|
||||
`*` Ensure you select the correct device on the page as it shows multiple options.
|
||||
|
||||
`†` This is optional and only required if you don't want to directly solder the ESP32 to the board, but I recommend it.
|
||||
`†` One of these sets is optional, and is useful if you do not want to solder the individual sensors directly to the board (see below).
|
||||
|
||||
`‡` Providing a price is impossible due to the wide range of possible fillament types and brands, but should be negligible.
|
||||
### To Solder or Not To Solder
|
||||
|
||||
I strongly encourage anyone building one of these units to leverage sockets for all components. First,
|
||||
this provides good spacing between components which can help with general better performance. It can
|
||||
also allow for quick swapping if any turn out to be defective or if future changes are warranted.
|
||||
|
||||
**If you use the [case](/case), it is sized assuming socketed components!** So for case users you
|
||||
must socket all components.
|
||||
|
||||
Note that due to the PCB design, you *must socket at least one* set of components - either the ESP32
|
||||
or the sensors on the front. Due to the positioning and overlap, it would be impossible to solder
|
||||
everything directly to the board, as the ESP covers several of the solder points of the front
|
||||
sensors and vice versa.
|
||||
|
||||
You can use the provided 40-pin female headers exclusively if you wish, and cut them to length for
|
||||
the individual sensors as needed, or you can use individually-sized female headers in the following
|
||||
quantities should you wish for a slightly neater finish:
|
||||
|
||||
* 3x 3-pin (AM302, INMP441 x2)
|
||||
* 2x 4-pin (SGP41, SHT45)
|
||||
* 1x 5-pin (LD2410C)
|
||||
* 1x 6-pin (TSL2591)
|
||||
|
||||
I will leave it up to the reader to source these specific sizes if they desire (I found all except
|
||||
a 5-pin on Amazon, and just used a 6-pin with one pin removed).
|
||||
|
||||
I still directly solder the RGB LEDs and resistor to the board for simplicity as these very small
|
||||
leads are not easily socketed, and these components are so inexpensive as to be effectively
|
||||
disposable along with the PCB should that be required.
|
||||
|
||||
### Part Swaps
|
||||
|
||||
To save a little money, it is possible to swap out the two Sensirion sensors for their less-feature-
|
||||
rich peers, with no code changes:
|
||||
|
||||
* SGP41 -> SGP40 - removes the NOx functionality
|
||||
* SHT45 -> SHT40/41/43 - less accuracy
|
||||
|
||||
Personally, I do not find the minimal cost savings to be worth sacrificing the extra potential
|
||||
functionality, so I recommend using the provided models, but this is up to the builder to decide.
|
||||
|
||||
No other parts can be easily swapped without code or PCB design changes.
|
||||
|
||||
## Air Quality Handling
|
||||
|
||||
The SuperSensor 2.0 features an SGP41 air quality sensor by Sensirion. This is a powerful AQ
|
||||
sensor which powers several commercial devices including the AirGradient One, which gave
|
||||
us a lot of our configuration via their sharing of algorithms.
|
||||
|
||||
The sensor provides two base readings: a VOC Index, and a NOx Index. These values are both
|
||||
floating references centered at 100 (VOC) and 1 (NOx), where that value represents "normal"
|
||||
air over the previous 24 hours. These sensors are very useful for any sort of quick-change
|
||||
automations, e.g. turn on a fan if levels spike due to cooking.
|
||||
|
||||
In addition, we leverage AirGradient's published forumulas to convert the VOC index into
|
||||
actual VOC quantities, in both µg/m³ and ppb. While this may drift due to the sensor's regular
|
||||
internal recalibration, I feel that following what AirGradient does is sufficient enough
|
||||
for any real-world home usage. Further, we use a very rough conversion of the aforementioned
|
||||
VOC quantity into an eCO2 reading, using Isobutylene as a reference gas. These sensors are
|
||||
more useful for display purposes, to show the current levels in a room in a dashboard or
|
||||
other such place, for human consumption. Note that no such conversions are done for NOx as
|
||||
there are no (that I can find) published empirical calculations for this conversion, unlike
|
||||
for VOCs via AirGradient.
|
||||
|
||||
Note however that like all MOx sensors, the SGP41 does not differentiate gasses, and as
|
||||
such cannot tell the difference between normal, everyday natural VOCs like those in
|
||||
breath or from e.g. ripening fruit, and dangerous VOCs from e.g. construction materials.
|
||||
It also reacts strongly to heavy humidity, resulting in higher values in such environments.
|
||||
These should be used only as a general indication of air quality over short periods, rather
|
||||
than an absolute reference over long periods (much to my own frustration but inevitable
|
||||
begruding acceptance).
|
||||
|
||||
## Room Health
|
||||
|
||||
The SuperSensor 2.0 leverages the outputs of the SHT45 and SGP41 sensors to calculate a
|
||||
"Room Health", expressed as a percentage, which represents how "healthy" i.e. comfortable
|
||||
a room is for a person to be in.
|
||||
|
||||
The room health is calculated based on the VOC level, temperature, and relative humidity.
|
||||
First, the raw value is converted to a per-sensor 100-0 scale as follows:
|
||||
|
||||
* For VOC levels, there is a set of linear scales based on common VOC level
|
||||
mappings, such that less than 200 ppb is 100, 200-400 maps to 100-90,
|
||||
400-600 maps to 90-70, 600-1500 maps to 70-40, 1500-3000 maps to 40-0, and
|
||||
greater than 3000 is 0.
|
||||
* For temperature and humidity, there is a single linear scale based on a
|
||||
configurable penalty value, such that a value between the configurable
|
||||
minimum and maximum is 100, and each degree C or %RH outside of that range
|
||||
decreases the value by the penalty value.
|
||||
|
||||
Next, each indivdual per-sensor value is applied to the total 100-0 value by a configurable
|
||||
weight, with the defaults being 40% to VOC level, 30% to temperature, and 30% to humidity. The
|
||||
values can never total more than 100% or total to 0% but are otherwise normalized (i.e. decrease
|
||||
others before increasing one, or the values will not be accepted; and at least one weight
|
||||
must be >0).
|
||||
|
||||
The final result is thus a 100-0% range that, in broad strokes, describes the overall
|
||||
health of the room. For some examples, assuming all of the default values below:
|
||||
|
||||
* Perfect: Temp 23C, humidity 50%RH, and VOC level 150ppb = 100% health
|
||||
* A little warm: Temp 25C (+1), humidity 50%RH, and VOC level 250ppb = 97% health
|
||||
* Dry: Temp 22C, humidity 30%RH (-10), VOC level 150ppb = 91% health
|
||||
* Dirty air: Temp 23C, humidity 50%RH, VOC level 800ppb = 85% health
|
||||
* Hot & humid: Temp 28C, humidity 70%RH, VOC level 250ppb = 84% health
|
||||
* All-around bad: Temp 30C, humidity 30%RH, VOC level 2000ppb = 52% health
|
||||
|
||||
These are then mapped to textual values as well with the following bands:
|
||||
|
||||
* 100%-95%: Great
|
||||
* 95%-90%: Good
|
||||
* 90%-80%: Fair
|
||||
* 80%-60%: Poor
|
||||
* 60%-0%: Bad
|
||||
|
||||
As mentioned above, most portions of this are configurable; see the section below for
|
||||
specific details of each configuration value.
|
||||
|
||||
## Configurable Options
|
||||
|
||||
@@ -102,33 +203,36 @@ configurable. See [the documentation](https://esphome.io/components/sensor/ld241
|
||||
### Enable Voice Support (switch)
|
||||
|
||||
If enabled (the default), the SuperSensor's voice functionality including
|
||||
wake word will be started. Disabling this defeats most of the point of the
|
||||
SuperSensor, but can be done if desired, for instance if you have multiple
|
||||
SuperSensors in a single room and only want one to respond to voice commands.
|
||||
wake word will be started, or it can be disabled to use the SuperSensor
|
||||
purely as a presence/environmental sensor.
|
||||
|
||||
### Enable Presence LED (switch)
|
||||
|
||||
If enabled (the default), when overall presence is detected, the LEDs will
|
||||
glow "white" at 15% power to signal presence.
|
||||
|
||||
### Temperature Offset (selector, -7 to +3 @ 0.1)
|
||||
### Temperature Offset (number, -30 to +10 @ 0.1, -5 default)
|
||||
|
||||
Allows calibration of the SHT45 temperature sensor with an offset from -7 to +3
|
||||
degrees C. Useful if the sensor is misreporting actual ambient tempreatures.
|
||||
Allows calibration of the SHT45 temperature sensor with an offset from -30 to +10
|
||||
degrees C. Useful if the sensor is misreporting actual ambient tempreatures. Due
|
||||
to internal heating of the SHT45 by the ESP32, this defaults to -5; further
|
||||
calibration may be needed for your sensors and environment based on an external
|
||||
reference.
|
||||
|
||||
### Humidity Offset (selector, -10 to +10 @ 0.1)
|
||||
### Humidity Offset (number, -20 to +20 @ 0.1)
|
||||
|
||||
Allows calibration of the SHT45 humidity sensor with an offset from -10 to +10
|
||||
percent relative humidity. Useful if the sensor is misreporting actual humidity.
|
||||
percent relative humidity. Useful if the sensor is misreporting actual humidity
|
||||
based on an external reference.
|
||||
|
||||
### PIR Hold Time (selector, 0 to +60 @ 5, 0 default)
|
||||
### PIR Hold Time (number, 0 to +60 @ 5, 0 default)
|
||||
|
||||
The SuperSensor uses an AM312 PIR sensor, which has a stock hold time of ~2.5
|
||||
seconds. This setting allows increasing that value, with retrigger support, to
|
||||
up to 60 seconds, allowing the PIR detection to report for longer. 0 represents
|
||||
"as long as the AM312 fires".
|
||||
|
||||
### Light Threshold Control (selector, 0 to +200 @ 5, 30 default)
|
||||
### Light Threshold Control (number, 0 to +200 @ 5, 30 default)
|
||||
|
||||
The SuperSensor features a "light presence" binary sensor based on the light
|
||||
level reported by the TSL2591 sensor. This control defines the minimum lux
|
||||
@@ -139,158 +243,75 @@ of say 30 lux: then, while the light is on, "light presence" is detected,
|
||||
and when the light is off, "light presence" is cleared. Light presence can
|
||||
be used standalone or as part of the integrated occupancy sensor (below).
|
||||
|
||||
### Integrated Occupancy Sensor (Selector)
|
||||
### Integrated Occupancy Sensor (selector)
|
||||
|
||||
The SuperSensor features a fully integrated "occupancy" sensor, which can be
|
||||
configured to provide exactly the sort of occupancy detection you may want
|
||||
for your room.
|
||||
|
||||
There are 7 options (plus "None"/disabled), with both "detect" and "clear"
|
||||
handled separately:
|
||||
handled separately. Occupancy is always detected when ALL of the selected
|
||||
sensors report detection, and occupancy is always cleared when ANY of the
|
||||
selected sensors stop reporting detection (logical AND in, logical OR out).
|
||||
|
||||
#### PIR + Radar + Light
|
||||
* PIR + Radar + Light
|
||||
* PIR + Radar
|
||||
* PIR + Light
|
||||
* Radar + Light
|
||||
* PIR Only
|
||||
* Radar Only
|
||||
* Light Only
|
||||
* None
|
||||
|
||||
Occupancy is detected when all 3 sensors report detected, and occupancy is
|
||||
cleared when any of the sensors report cleared.
|
||||
### Room Health Sensor
|
||||
|
||||
For detect, this provides the most "safety" against misfires, but requires
|
||||
a normally-dark room with a non-automated light source and clear PIR
|
||||
detection positioning.
|
||||
#### Minimum Temperature (number, 15 to 30 @ 0.5, 21 default)
|
||||
|
||||
For clear, this option is probably not very useful as it is likely to clear
|
||||
quite frequently from the PIR, but is provided for completeness.
|
||||
The lower bounds of a fully comfortable temperature; temperature values below
|
||||
this value will begin decreasing the room health score.
|
||||
|
||||
#### PIR + Radar
|
||||
#### Maximum Temperature (number, 15 to 30 @ 0.5, 24 default)
|
||||
|
||||
Occupancy is detected when both sensors report detected, and occupancy is
|
||||
cleared when either of the sensors report cleared.
|
||||
The upper bounds of a fully comfortable temperature; temperature values above
|
||||
this value will begin decreasing the room health score.
|
||||
|
||||
For detect, this provides good "safety" against PIR misfires without
|
||||
needing a normally-dark room, though detection may be slightly delayed
|
||||
from either sensor.
|
||||
#### Temperature Penalty (number, 1 to 20 @ 1, 10 default)
|
||||
|
||||
For clear, this option is probably not very useful as it is likely to clear
|
||||
quite frequently from the PIR, but is provided for completeness.
|
||||
The penalty value per degree of temperature deviation from ideal levels, applied
|
||||
to the pre-weighting value for temperature.
|
||||
|
||||
#### PIR + Light
|
||||
#### Minimum Humidity (number, 20 to 80 @ 1, 40 default)
|
||||
|
||||
Occupancy is detected when both sensors report detected, and occupancy is
|
||||
cleared when either of the sensors report cleared.
|
||||
The lower bounds of a fully comfortable relative humidity level; relative
|
||||
humidity values below this value will begin decreasing the room health score.
|
||||
|
||||
For detect, this provides some "safety" against PIR misfires, but requires
|
||||
a normally-dark room with a non-automated light source and clear PIR
|
||||
detection positioning.
|
||||
#### Maximum Humidity (number, 20 to 80 @ 1, 60 default)
|
||||
|
||||
For clear, this option is probably not very useful as it is likely to clear
|
||||
quite frequently from the PIR, but is provided for completeness.
|
||||
The upper bounds of a fully comfortable relative humidity level; relative
|
||||
humidity values above this value will begin decreasing the room health score.
|
||||
|
||||
#### Radar + Light
|
||||
#### Humidity Penalty (number, 1 to 10 @ 1, 5 default)
|
||||
|
||||
Occupancy is detected when both sensors report detected, and occupancy is
|
||||
cleared when either of the sensors report cleared.
|
||||
The penalty value per % of relative humidity deviation from ideal levels, applied
|
||||
to the pre-weighting value for humidity.
|
||||
|
||||
For detect, this allows for radar detection while suppressing occupancy
|
||||
without light, for instance in a hallway where one might not want a late
|
||||
night bathroom visit to turn on the lights, or something to that effect.
|
||||
#### VOC Weight (number, 0.0 to 1.0, 0.4 default)
|
||||
|
||||
For clear, this option can provide a useful option to clear presence
|
||||
quickly if the lights go out, while still providing Radar presence.
|
||||
The weighting value of the VOC score relative to the other two for calculating
|
||||
the total room health.
|
||||
|
||||
#### PIR Only
|
||||
Note: Cannot exceed 0.4 without first decreasing one of the other weights (total max of 1.0).
|
||||
|
||||
Occupancy is based entirely on the PIR sensor for both detect and clear.
|
||||
#### Temperature Weight (number, 0.0 to 1.0, 0.3 default)
|
||||
|
||||
Prone to misfires, but otherwise a good option for quick detection and
|
||||
clearance in a primarily-moving zone (e.g. hallway).
|
||||
The weighting value of the Temperature score relative to the other two for
|
||||
calculating the total room health.
|
||||
|
||||
#### Radar Only
|
||||
Note: Cannot exceed 0.3 without first decreasing one of the other weights (total max of 1.0).
|
||||
|
||||
Occupancy is based entirely on the Radar sensor for both detect and clear.
|
||||
#### Humidity Weight (number, 0.0 to 1.0, 0.3 default)
|
||||
|
||||
Useful for an area with no consistent motion or light level.
|
||||
The weighting value of the Humidity score relative to the other two for calculating
|
||||
the total room health.
|
||||
|
||||
#### Light Only
|
||||
|
||||
Occupancy is based entirely on the Light sensor for both detect and clear.
|
||||
|
||||
Useful for full dependence on an external light source.
|
||||
|
||||
#### None
|
||||
|
||||
Disable the functionality in either direction.
|
||||
|
||||
For detect, no occupancy will ever fire.
|
||||
|
||||
For clear, no states will clear occupancy; with any detect option, this
|
||||
means that occupancy will be detected only once and never clear, which
|
||||
is likely not useful.
|
||||
|
||||
## AQ Details
|
||||
|
||||
The SuperSensor 2.x provides 2 base air quality sensors (numeric), from which
|
||||
4 human-readable text sensors are derived.
|
||||
|
||||
The goal of these sensors is to track general comfort and livability in a
|
||||
room, not specific contaminants or conditions. Because the SGP30 can only
|
||||
track TVOC and eCO2, we do not track particulates, CO, NOx, or CH2O, all
|
||||
of which are required for a full EPA (I)AQI score. This means the best
|
||||
we can do is approximate (I)AQI roughly, and since a scale of 0-500 based
|
||||
on approximations seems pointless, I went with much simpler 1-4/5 scores
|
||||
instead. I feel this does a good enough job to be useful for 99% of rooms.
|
||||
|
||||
We also cannot really debate whether the BME680 is actually any more accurate
|
||||
in this regard, since their algorithms are proprietary and all that is exposed
|
||||
normally is a single resistance value, so in my opinion this is actually
|
||||
superior to that sensor anyways with two discrete datapoints (versus one),
|
||||
even if it does still seem limited when compared to dedicated AQ sensors.
|
||||
And that is to say nothing of the issues with that sensor (constantly climbing
|
||||
IAQ values over time, poor calibration, etc.).
|
||||
|
||||
### Base Numeric Values
|
||||
|
||||
#### IAQ Index (1-5)
|
||||
|
||||
The IAQ index is calculated based on the TVOC and eCO2 values from the SGP30
|
||||
sensor, to provide 5 levels of air quality. This corresponds approximately
|
||||
to the levels provided by the BME680 (0-50, 50-100, 100-200, 200-300, 300+).
|
||||
|
||||
5 is "excellent": the TVOC is <65 ppb and the eCO2 is <600 ppm.
|
||||
4 is "good": the TVOC is 65-220 ppb or the eCO2 is 600-800 ppm.
|
||||
3 is "moderate": the TVOC is 220-660 ppb or the eCO2 is 800-1200 ppm.
|
||||
2 is "poor": the TVOC is 660-2200 ppb or the eCO2 is 1200-2000 ppm.
|
||||
1 is "unhealthy": the TVOC is >2200 ppb or the eCO2 is >2000 ppm.
|
||||
|
||||
#### Room Health Score (1-4)
|
||||
|
||||
The Room Health Score is calculated based on the IAQ, temperature, and humidity,
|
||||
and is designed to show how "nice" a room is to be in. Generally a 4 is a nice
|
||||
place to be, especially for someone with respiratory issues like myself, and lower
|
||||
scores indicate more deviations from the norms or poor IAQ.
|
||||
|
||||
4 is "optimal": IAQ is >= 4 ("excellent" or "good"), temperature is between 18C and 24C, and humidity is between 40% and 60%.
|
||||
3 is "fair": One of the above is not true, and IAQ is >= 3 ("moderate").
|
||||
2 is "poor": Two of the above are not true, and IAQ is >= 2 ("poor").
|
||||
1 is "bad": All of the above are not true or IAQ is 1 ("unhealthy") regardless of other values.
|
||||
|
||||
Note that IAQ levels hold a major sway over this level, and decreasing IAQ
|
||||
scores will push the room score lower regardless of temperature or humidity.
|
||||
It is best used together with the individual sensors to determine exactly
|
||||
what is wrong with the room.
|
||||
|
||||
### Derived Text Sensors
|
||||
|
||||
#### VOC Level
|
||||
|
||||
This reports the VOC level alone, based on the scale under IAQ Index, in textual form ("Excellent, "Good", etc.).
|
||||
|
||||
#### CO2 Level
|
||||
|
||||
This reports the eCO2 level alone, based on the scale under IAQ Index, in textual form ("Excellent, Good", etc.).
|
||||
|
||||
#### IAQ Classification
|
||||
|
||||
This reports the IAQ Index in textual form ("Excellent", "Good", etc.).
|
||||
|
||||
#### Room Health
|
||||
|
||||
This reports the Room Health Score in textual form ("Optimal", "Fair", "Poor", "Bad").
|
||||
Note: Cannot exceed 0.3 without first decreasing one of the other weights (total max of 1.0).
|
||||
|
5
archive/.gitignore
vendored
@@ -1,5 +0,0 @@
|
||||
# Gitignore settings for ESPHome
|
||||
# This is an example and may include too much for your use-case.
|
||||
# You can modify this file to suit your needs.
|
||||
/.esphome/
|
||||
/secrets.yaml
|
@@ -1,393 +0,0 @@
|
||||
---
|
||||
|
||||
###############################################################################
|
||||
# SuperSensor v1.0 ESPHome configuration
|
||||
###############################################################################
|
||||
#
|
||||
# Copyright (C) 2023 Joshua M. Boniface <joshua@boniface.me>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
substitutions:
|
||||
# How long a PIR activation should be held for
|
||||
pir_holdtime: "15s"
|
||||
|
||||
esphome:
|
||||
name: supersensor
|
||||
name_add_mac_suffix: true
|
||||
friendly_name: "Supersensor"
|
||||
project:
|
||||
name: joshuaboniface.supersensor
|
||||
version: "0.1"
|
||||
includes:
|
||||
- veml7700.h
|
||||
libraries:
|
||||
- "Wire"
|
||||
- "Adafruit Unified Sensor"
|
||||
- "SPI"
|
||||
- "Adafruit BusIO"
|
||||
- "Adafruit VEML7700 Library"
|
||||
on_boot:
|
||||
- priority: 600
|
||||
then:
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
effect: flash
|
||||
red: 1
|
||||
green: 1
|
||||
blue: 1
|
||||
|
||||
dashboard_import:
|
||||
package_import_url: github://joshuaboniface/supersensor/supersensor.yaml
|
||||
import_full_config: false
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
# framework:
|
||||
# type: esp-idf
|
||||
# sdkconfig_options:
|
||||
# CONFIG_ESP32_DEFAULT_CPU_FREQ_240: "y"
|
||||
# CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ: "240"
|
||||
# CONFIG_ESP32_DATA_CACHE_64KB: "y"
|
||||
# CONFIG_ESP32_DATA_CACHE_LINE_64B: "y"
|
||||
# CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: "y"
|
||||
# CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ: "240"
|
||||
# CONFIG_ESP32S3_DATA_CACHE_64KB: "y"
|
||||
# CONFIG_ESP32S3_DATA_CACHE_LINE_64B: "y"
|
||||
|
||||
script:
|
||||
- id: pir_handler
|
||||
then:
|
||||
- lambda: |-
|
||||
id(pir_motion).publish_state(true);
|
||||
- while:
|
||||
condition:
|
||||
binary_sensor.is_on: pir_gpio
|
||||
then:
|
||||
- delay: ${pir_holdtime}
|
||||
- lambda: |-
|
||||
id(pir_motion).publish_state(false);
|
||||
|
||||
# Enable logging only via web
|
||||
logger:
|
||||
level: DEBUG
|
||||
baud_rate: 0
|
||||
|
||||
api:
|
||||
encryption:
|
||||
key: !secret api_encryption_key
|
||||
on_client_disconnected:
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
effect: flash
|
||||
red: 1
|
||||
green: 1
|
||||
blue: 1
|
||||
- switch.turn_off: use_wake_word
|
||||
on_client_connected:
|
||||
- switch.turn_on: use_wake_word
|
||||
- delay: 2s
|
||||
- switch.turn_off: use_wake_word
|
||||
- delay: 2s
|
||||
- switch.turn_on: use_wake_word
|
||||
- delay: 2s
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
|
||||
ota:
|
||||
password: !secret ota_password
|
||||
safe_mode: false
|
||||
|
||||
web_server:
|
||||
port: 80
|
||||
auth:
|
||||
username: !secret web_auth_username
|
||||
password: !secret web_auth_password
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
domain: !secret wifi_domain
|
||||
power_save_mode: LIGHT
|
||||
reboot_timeout: 5min
|
||||
|
||||
uart:
|
||||
id: LD1115H_UART_BUS
|
||||
rx_pin: GPIO3
|
||||
tx_pin: GPIO1
|
||||
baud_rate: 115200
|
||||
setup_priority: 200
|
||||
|
||||
i2c:
|
||||
sda: GPIO21
|
||||
scl: GPIO22
|
||||
scan: true
|
||||
|
||||
i2s_audio:
|
||||
i2s_lrclk_pin: GPIO25
|
||||
i2s_bclk_pin: GPIO26
|
||||
|
||||
microphone:
|
||||
- platform: i2s_audio
|
||||
id: mic
|
||||
adc_type: external
|
||||
i2s_din_pin: GPIO27
|
||||
pdm: false
|
||||
|
||||
voice_assistant:
|
||||
microphone: mic
|
||||
use_wake_word: false
|
||||
noise_suppression_level: 2
|
||||
auto_gain: 31dBFS
|
||||
volume_multiplier: 4.0
|
||||
id: assist
|
||||
on_error:
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
transition_length: 1s
|
||||
- logger.log: "Voice Assistant encountered an error; restarting it"
|
||||
- switch.turn_off: use_wake_word
|
||||
- delay: 1s
|
||||
- switch.turn_on: use_wake_word
|
||||
on_wake_word_detected:
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
red: 0
|
||||
green: 0
|
||||
blue: 1
|
||||
on_listening:
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
red: 0
|
||||
green: 0
|
||||
blue: 1
|
||||
on_stt_end:
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
transition_length: 1s
|
||||
on_tts_start:
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
transition_length: 1s
|
||||
- if:
|
||||
condition:
|
||||
lambda: return x != "Sorry, I couldn't understand that";
|
||||
then:
|
||||
- logger.log: "Command successful!"
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
effect: hold
|
||||
red: 0
|
||||
green: 1
|
||||
blue: 0
|
||||
else:
|
||||
- logger.log: "Command failed!"
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
effect: hold
|
||||
red: 1
|
||||
green: 0
|
||||
blue: 0
|
||||
|
||||
light:
|
||||
- platform: rgb
|
||||
id: output_led
|
||||
red: rgb_r
|
||||
green: rgb_g
|
||||
blue: rgb_b
|
||||
default_transition_length: 0.15s
|
||||
flash_transition_length: 0.15s
|
||||
effects:
|
||||
- strobe:
|
||||
name: flash
|
||||
colors:
|
||||
- state: true
|
||||
duration: 0.5s
|
||||
- state: false
|
||||
duration: 0.5s
|
||||
- automation:
|
||||
name: hold
|
||||
sequence:
|
||||
- delay: 5s
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
transition_length: 1s
|
||||
|
||||
output:
|
||||
- platform: ledc
|
||||
id: rgb_r
|
||||
pin: GPIO14
|
||||
- platform: ledc
|
||||
id: rgb_g
|
||||
pin: GPIO12
|
||||
- platform: ledc
|
||||
id: rgb_b
|
||||
pin: GPIO13
|
||||
|
||||
button:
|
||||
- platform: restart
|
||||
name: "ESP32 Restart"
|
||||
icon: mdi:power-cycle
|
||||
entity_category: "diagnostic"
|
||||
|
||||
switch:
|
||||
- platform: template
|
||||
name: "Enable Wake Word"
|
||||
icon: mdi:account-voice
|
||||
id: use_wake_word
|
||||
optimistic: true
|
||||
restore_mode: ALWAYS_OFF
|
||||
entity_category: config
|
||||
on_turn_on:
|
||||
- lambda: id(assist).set_use_wake_word(true);
|
||||
- if:
|
||||
condition:
|
||||
not:
|
||||
- voice_assistant.is_running
|
||||
then:
|
||||
- voice_assistant.start_continuous
|
||||
on_turn_off:
|
||||
- voice_assistant.stop
|
||||
- lambda: id(assist).set_use_wake_word(false);
|
||||
|
||||
binary_sensor:
|
||||
- platform: gpio
|
||||
name: "PIR GPIO"
|
||||
id: pir_gpio
|
||||
pin: GPIO33
|
||||
internal: false
|
||||
device_class: motion
|
||||
on_press:
|
||||
- script.stop: pir_handler
|
||||
- script.execute: pir_handler
|
||||
|
||||
- platform: template
|
||||
name: "PIR Motion"
|
||||
id: pir_motion
|
||||
device_class: motion
|
||||
|
||||
- platform: gpio
|
||||
name: "LD1115H Presence"
|
||||
id: ld11115h_gpio
|
||||
pin: GPIO23
|
||||
internal: false
|
||||
device_class: motion
|
||||
|
||||
sensor:
|
||||
# - platform: bme280
|
||||
# temperature:
|
||||
# name: "BME280 Temperature"
|
||||
# pressure:
|
||||
# name: "BME280 Pressure"
|
||||
# humidity:
|
||||
# name: "BME280 Humidity"
|
||||
# update_interval: 15s
|
||||
# address: 0x76
|
||||
|
||||
- platform: bmp280
|
||||
temperature:
|
||||
name: "BMP280 Temperature"
|
||||
pressure:
|
||||
name: "BMP280 Pressure"
|
||||
update_interval: 5s
|
||||
address: 0x76
|
||||
|
||||
- platform: custom
|
||||
lambda: |-
|
||||
auto veml7700 = new VEML7700CustomSensor();
|
||||
App.register_component(veml7700);
|
||||
return {veml7700->lux_sensor};
|
||||
sensors:
|
||||
- name: "VEML7700 Illumination"
|
||||
unit_of_measurement: Lux
|
||||
accuracy_decimals: 0
|
||||
|
||||
- platform: uptime
|
||||
name: "ESP32 Uptime"
|
||||
icon: mdi:clock-alert
|
||||
update_interval: 5s
|
||||
entity_category: "diagnostic"
|
||||
|
||||
- platform: wifi_signal
|
||||
name: "ESP32 WiFi RSSI"
|
||||
icon: mdi:wifi-strength-2
|
||||
update_interval: 5s
|
||||
entity_category: "diagnostic"
|
||||
|
||||
- platform: internal_temperature
|
||||
name: "ESP32 Temperature"
|
||||
icon: mdi:thermometer
|
||||
unit_of_measurement: °C
|
||||
device_class: TEMPERATURE
|
||||
update_interval: 5s
|
||||
entity_category: "diagnostic"
|
||||
|
||||
- platform: template
|
||||
name: "ESP32 CPU Frequency"
|
||||
icon: mdi:cpu-32-bit
|
||||
accuracy_decimals: 1
|
||||
unit_of_measurement: MHz
|
||||
update_interval: 5s
|
||||
lambda: |-
|
||||
return ets_get_cpu_frequency();
|
||||
entity_category: "diagnostic"
|
||||
|
||||
- platform: template
|
||||
name: "ESP32 Free Memory"
|
||||
icon: mdi:memory
|
||||
unit_of_measurement: 'kB'
|
||||
state_class: measurement
|
||||
update_interval: 5s
|
||||
lambda: |-
|
||||
return heap_caps_get_free_size(MALLOC_CAP_INTERNAL) / 1024;
|
||||
entity_category: "diagnostic"
|
||||
|
||||
number:
|
||||
- platform: template
|
||||
name: LD1115H TH1 #TH1 is Movement/Motion Sensitivity
|
||||
id: LD1115H_TH1
|
||||
icon: "mdi:cogs"
|
||||
optimistic: true
|
||||
restore_value: true #If you don't want to store the setting at ESP, set it to false.
|
||||
initial_value: "120" #Default TH1 Setting
|
||||
min_value: 20
|
||||
max_value: 1200
|
||||
step: 10
|
||||
set_action:
|
||||
then:
|
||||
- uart.write:
|
||||
id: LD1115H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string th1st = "th1=" + str_sprintf("%.0f",x) +" \n";
|
||||
return std::vector<uint8_t>(th1st.begin(), th1st.end());
|
||||
- platform: template
|
||||
name: LD1115H TH2 #TH2 is Occupancy/Presence Sensitivity
|
||||
id: LD1115H_TH2
|
||||
icon: "mdi:cogs"
|
||||
optimistic: true
|
||||
restore_value: true #If you don't want to store the setting at ESP, set it to false.
|
||||
initial_value: "250" #Default TH2 Setting
|
||||
min_value: 50
|
||||
max_value: 2500
|
||||
step: 10
|
||||
set_action:
|
||||
then:
|
||||
- uart.write:
|
||||
id: LD1115H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string th2st = "th2=" + str_sprintf("%.0f",x) +" \n";
|
||||
return std::vector<uint8_t>(th2st.begin(), th2st.end());
|
@@ -1,651 +0,0 @@
|
||||
---
|
||||
|
||||
###############################################################################
|
||||
# SuperSensor v1.0 ESPHome configuration
|
||||
###############################################################################
|
||||
#
|
||||
# Copyright (C) 2023 Joshua M. Boniface <joshua@boniface.me>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
#
|
||||
# Compile-time Substitutions
|
||||
#
|
||||
substitutions:
|
||||
ignored_radar_ranges: |-
|
||||
{
|
||||
{ 2.20, 3.30 },
|
||||
{ 2.20, 2.75 }
|
||||
}
|
||||
|
||||
#
|
||||
# Core configuration
|
||||
#
|
||||
esphome:
|
||||
name: supersensor
|
||||
name_add_mac_suffix: true
|
||||
on_boot:
|
||||
- priority: 600
|
||||
then:
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
effect: flash
|
||||
red: 1
|
||||
green: 1
|
||||
blue: 1
|
||||
|
||||
- priority: 100
|
||||
then:
|
||||
# Configure LD1125H via UART
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string mth1_mov_st = "mth1_mov=" + str_sprintf("%.0f",id(LD1125H_mth1_mov).state) + "\r\n";
|
||||
return std::vector<uint8_t>(mth1_mov_st.begin(), mth1_mov_st.end());
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string mth2_mov_st = "mth2_mov=" + str_sprintf("%.0f",id(LD1125H_mth2_mov).state) + "\r\n";
|
||||
return std::vector<uint8_t>(mth2_mov_st.begin(), mth2_mov_st.end());
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string mth3_mov_st = "mth3_mov=" + str_sprintf("%.0f",id(LD1125H_mth3_mov).state) + "\r\n";
|
||||
return std::vector<uint8_t>(mth3_mov_st.begin(), mth3_mov_st.end());
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string mth1_occ_st = "mth1_occ=" + str_sprintf("%.0f",id(LD1125H_mth1_occ).state) + "\r\n";
|
||||
return std::vector<uint8_t>(mth1_occ_st.begin(), mth1_occ_st.end());
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string mth2_occ_st = "mth2_occ=" + str_sprintf("%.0f",id(LD1125H_mth2_occ).state) + "\r\n";
|
||||
return std::vector<uint8_t>(mth2_occ_st.begin(), mth2_occ_st.end());
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string mth3_occ_st = "mth3_occ=" + str_sprintf("%.0f",id(LD1125H_mth3_occ).state) + "\r\n";
|
||||
return std::vector<uint8_t>(mth3_occ_st.begin(), mth3_occ_st.end());
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string rmaxst = "rmax=" + str_sprintf("%.1f",id(LD1125H_rmax).state) + "\r\n";
|
||||
return std::vector<uint8_t>(rmaxst.begin(), rmaxst.end());
|
||||
|
||||
- priority: -500
|
||||
then:
|
||||
- wait_until: api.connected
|
||||
- delay: 3s
|
||||
- switch.turn_on: use_wake_word
|
||||
- delay: 2s
|
||||
- switch.turn_off: use_wake_word
|
||||
- delay: 2s
|
||||
- switch.turn_on: use_wake_word
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
framework:
|
||||
type: esp-idf
|
||||
sdkconfig_options:
|
||||
CONFIG_ESP32_DEFAULT_CPU_FREQ_240: "y"
|
||||
CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ: "240"
|
||||
CONFIG_ESP32_DATA_CACHE_64KB: "y"
|
||||
CONFIG_ESP32_DATA_CACHE_LINE_64B: "y"
|
||||
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: "y"
|
||||
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ: "240"
|
||||
CONFIG_ESP32S3_DATA_CACHE_64KB: "y"
|
||||
CONFIG_ESP32S3_DATA_CACHE_LINE_64B: "y"
|
||||
|
||||
external_components:
|
||||
- source:
|
||||
type: git
|
||||
url: https://github.com/ssieb/custom_components
|
||||
components: [ serial ]
|
||||
|
||||
logger:
|
||||
level: VERBOSE
|
||||
baud_rate: 115200
|
||||
|
||||
api:
|
||||
encryption:
|
||||
key: !secret api_encryption_key
|
||||
|
||||
ota:
|
||||
password: !secret ota_password
|
||||
safe_mode: false
|
||||
|
||||
web_server:
|
||||
port: 80
|
||||
auth:
|
||||
username: !secret web_auth_username
|
||||
password: !secret web_auth_password
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
domain: !secret wifi_domain
|
||||
power_save_mode: LIGHT
|
||||
reboot_timeout: 5min
|
||||
|
||||
uart:
|
||||
id: LD1125H_UART_BUS
|
||||
rx_pin: GPIO18
|
||||
tx_pin: GPIO19
|
||||
setup_priority: 200
|
||||
baud_rate: 115200
|
||||
data_bits: 8
|
||||
stop_bits: 1
|
||||
parity: NONE
|
||||
|
||||
i2c:
|
||||
sda: GPIO21
|
||||
scl: GPIO22
|
||||
scan: true
|
||||
|
||||
#
|
||||
# Radar Globals
|
||||
#
|
||||
globals:
|
||||
- id: LD1125H_Last_Update_Time
|
||||
type: uint32_t
|
||||
restore_value: no
|
||||
initial_value: millis()
|
||||
- id: LD1125H_Last_Time
|
||||
type: time_t
|
||||
restore_value: no
|
||||
initial_value: time(NULL)
|
||||
- id: LD1125H_Last_Mov_Time
|
||||
type: time_t
|
||||
restore_value: no
|
||||
initial_value: time(NULL)
|
||||
- id: LD1125H_Clearance_Status
|
||||
type: bool
|
||||
restore_value: no
|
||||
initial_value: "false"
|
||||
- id: ignored_ranges
|
||||
type: std::vector<std::vector<float>>
|
||||
restore_value: no
|
||||
initial_value: ${ignored_radar_ranges}
|
||||
|
||||
#
|
||||
# Voice Control
|
||||
#
|
||||
i2s_audio:
|
||||
i2s_lrclk_pin: GPIO25
|
||||
i2s_bclk_pin: GPIO26
|
||||
|
||||
microphone:
|
||||
- platform: i2s_audio
|
||||
id: mic
|
||||
adc_type: external
|
||||
i2s_din_pin: GPIO27
|
||||
pdm: false
|
||||
|
||||
voice_assistant:
|
||||
microphone: mic
|
||||
use_wake_word: false
|
||||
noise_suppression_level: 2
|
||||
auto_gain: 31dBFS
|
||||
volume_multiplier: 5.0
|
||||
id: assist
|
||||
on_wake_word_detected:
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
red: 0
|
||||
green: 0
|
||||
blue: 1
|
||||
on_listening:
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
red: 0
|
||||
green: 0
|
||||
blue: 1
|
||||
on_stt_end:
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
transition_length: 1s
|
||||
on_tts_start:
|
||||
- if:
|
||||
condition:
|
||||
lambda: return x != "Sorry, I couldn't understand that";
|
||||
then:
|
||||
- logger.log: "Command successful!"
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
effect: hold
|
||||
red: 0
|
||||
green: 1
|
||||
blue: 0
|
||||
else:
|
||||
- logger.log: "Command failed!"
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
effect: hold
|
||||
red: 1
|
||||
green: 0
|
||||
blue: 0
|
||||
|
||||
#
|
||||
# Voice Response LED
|
||||
#
|
||||
light:
|
||||
- platform: rgb
|
||||
id: output_led
|
||||
red: rgb_r
|
||||
green: rgb_g
|
||||
blue: rgb_b
|
||||
default_transition_length: 0.15s
|
||||
flash_transition_length: 0.15s
|
||||
effects:
|
||||
- strobe:
|
||||
name: flash
|
||||
colors:
|
||||
- state: true
|
||||
duration: 0.5s
|
||||
- state: false
|
||||
duration: 0.5s
|
||||
- automation:
|
||||
name: hold
|
||||
sequence:
|
||||
- delay: 5s
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
transition_length: 1s
|
||||
|
||||
output:
|
||||
- platform: ledc
|
||||
id: rgb_r
|
||||
pin: GPIO14
|
||||
- platform: ledc
|
||||
id: rgb_g
|
||||
pin: GPIO12
|
||||
- platform: ledc
|
||||
id: rgb_b
|
||||
pin: GPIO13
|
||||
|
||||
#
|
||||
# Restart button
|
||||
#
|
||||
button:
|
||||
- platform: restart
|
||||
name: "ESP32 Restart"
|
||||
icon: mdi:power-cycle
|
||||
entity_category: "diagnostic"
|
||||
|
||||
#
|
||||
# Wake Word switch
|
||||
#
|
||||
switch:
|
||||
- platform: template
|
||||
name: "Voice Enable Wake Word"
|
||||
icon: mdi:account-voice
|
||||
id: use_wake_word
|
||||
optimistic: true
|
||||
restore_mode: ALWAYS_OFF
|
||||
entity_category: config
|
||||
on_turn_on:
|
||||
- lambda: id(assist).set_use_wake_word(true);
|
||||
- if:
|
||||
condition:
|
||||
not:
|
||||
- voice_assistant.is_running
|
||||
then:
|
||||
- voice_assistant.start_continuous
|
||||
on_turn_off:
|
||||
- voice_assistant.stop
|
||||
- lambda: id(assist).set_use_wake_word(false);
|
||||
|
||||
#
|
||||
# Motion Sensors
|
||||
#
|
||||
binary_sensor:
|
||||
- platform: gpio
|
||||
pin: GPIO33
|
||||
name: "PIR Motion"
|
||||
device_class: motion
|
||||
|
||||
- platform: template
|
||||
name: "LD1125H Occupancy & Movement"
|
||||
id: LD1125H_MovOcc_Binary
|
||||
device_class: occupancy
|
||||
|
||||
- platform: template
|
||||
name: "LD1125H Motion"
|
||||
id: LD1125H_Mov_Binary
|
||||
device_class: motion
|
||||
|
||||
#
|
||||
# LD1125H Text Sensors
|
||||
#
|
||||
text_sensor:
|
||||
- platform: serial
|
||||
uart_id: LD1125H_UART_BUS
|
||||
name: "LD1125H UART Text"
|
||||
id: LD1125H_UART_Text
|
||||
icon: mdi:format-text
|
||||
internal: true
|
||||
on_value:
|
||||
then:
|
||||
- lambda: |-
|
||||
if ((millis() - id(LD1125H_Last_Update_Time)) < 1000) {
|
||||
return;
|
||||
} else {
|
||||
id(LD1125H_Last_Update_Time) = millis();
|
||||
}
|
||||
for (const auto& row : id(ignored_ranges)) {
|
||||
if ( ( atof(id(LD1125H_UART_Text).state.substr(9).c_str()) > row[0] ) && ( atof(id(LD1125H_UART_Text).state.substr(9).c_str()) < row[1] ) ) {
|
||||
break;
|
||||
} else {
|
||||
if (id(LD1125H_UART_Text).state.substr(0,3) == "occ") {
|
||||
id(LD1125H_Distance).publish_state(atof(id(LD1125H_UART_Text).state.substr(9).c_str()));
|
||||
if ((time(NULL)-id(LD1125H_Last_Mov_Time))>id(LD1125H_Mov_Time).state) {
|
||||
id(LD1125H_Occupancy).publish_state("Occupied");
|
||||
if (id(LD1125H_MovOcc_Binary).state == false) {
|
||||
id(LD1125H_MovOcc_Binary).publish_state(true);
|
||||
}
|
||||
if (id(LD1125H_Mov_Binary).state == true) {
|
||||
id(LD1125H_Mov_Binary).publish_state(false);
|
||||
}
|
||||
}
|
||||
if (id(LD1125H_MovOcc_Binary).state == false) {
|
||||
id(LD1125H_MovOcc_Binary).publish_state(true);
|
||||
}
|
||||
id(LD1125H_Last_Time) = time(NULL);
|
||||
if (id(LD1125H_Clearance_Status) == true) {
|
||||
id(LD1125H_Clearance_Status) = false;
|
||||
}
|
||||
}
|
||||
else if (id(LD1125H_UART_Text).state.substr(0,3) == "mov") {
|
||||
id(LD1125H_Distance).publish_state(atof(id(LD1125H_UART_Text).state.substr(9).c_str()));
|
||||
id(LD1125H_Occupancy).publish_state("Movement");
|
||||
if (id(LD1125H_MovOcc_Binary).state == false) {
|
||||
id(LD1125H_MovOcc_Binary).publish_state(true);
|
||||
}
|
||||
if (id(LD1125H_Mov_Binary).state == false) {
|
||||
id(LD1125H_Mov_Binary).publish_state(true);
|
||||
}
|
||||
id(LD1125H_Last_Mov_Time) = time(NULL);
|
||||
id(LD1125H_Last_Time) = time(NULL);
|
||||
if (id(LD1125H_Clearance_Status) == true) {
|
||||
id(LD1125H_Clearance_Status) = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- platform: template
|
||||
name: "LD1125H Occupancy Status"
|
||||
id: LD1125H_Occupancy
|
||||
icon: "mdi:motion-sensor"
|
||||
|
||||
|
||||
#
|
||||
# Other Sensors
|
||||
#
|
||||
sensor:
|
||||
# BME280 Temperature/Humidity/Pressure sensor
|
||||
- platform: bme280
|
||||
temperature:
|
||||
name: "BME280 Temperature"
|
||||
humidity:
|
||||
name: "BME280 Humidity"
|
||||
pressure:
|
||||
name: "BME280 Pressure"
|
||||
update_interval: 15s
|
||||
address: 0x76
|
||||
|
||||
# BMP280 Temperature/Pressure sensor (TEMPORARY)
|
||||
- platform: bmp280
|
||||
temperature:
|
||||
name: "BMP280 Temperature"
|
||||
pressure:
|
||||
name: "BMP280 Pressure"
|
||||
update_interval: 15s
|
||||
address: 0x76
|
||||
|
||||
# LD1125H Distance
|
||||
- platform: template
|
||||
name: LD1125H Detect Distance
|
||||
id: LD1125H_Distance
|
||||
icon: mdi:signal-distance-variant
|
||||
unit_of_measurement: "m"
|
||||
accuracy_decimals: 2
|
||||
|
||||
# Internal sensors
|
||||
- platform: uptime
|
||||
name: "ESP32 Uptime"
|
||||
icon: mdi:clock-alert
|
||||
update_interval: 15s
|
||||
entity_category: "diagnostic"
|
||||
|
||||
- platform: wifi_signal
|
||||
name: "ESP32 WiFi RSSI"
|
||||
icon: mdi:wifi-strength-2
|
||||
update_interval: 15s
|
||||
entity_category: "diagnostic"
|
||||
|
||||
- platform: internal_temperature
|
||||
name: "ESP32 Temperature"
|
||||
icon: mdi:thermometer
|
||||
unit_of_measurement: °C
|
||||
device_class: TEMPERATURE
|
||||
update_interval: 15s
|
||||
entity_category: "diagnostic"
|
||||
|
||||
- platform: template
|
||||
name: "ESP32 CPU Frequency"
|
||||
icon: mdi:cpu-32-bit
|
||||
accuracy_decimals: 1
|
||||
unit_of_measurement: MHz
|
||||
update_interval: 15s
|
||||
lambda: |-
|
||||
return ets_get_cpu_frequency();
|
||||
entity_category: "diagnostic"
|
||||
|
||||
- platform: template
|
||||
name: "ESP32 Free Memory"
|
||||
icon: mdi:memory
|
||||
unit_of_measurement: 'kB'
|
||||
state_class: measurement
|
||||
update_interval: 15s
|
||||
lambda: |-
|
||||
return heap_caps_get_free_size(MALLOC_CAP_INTERNAL) / 1024;
|
||||
entity_category: "diagnostic"
|
||||
|
||||
#
|
||||
# LD1125H tunables
|
||||
#
|
||||
number:
|
||||
- platform: template
|
||||
name: "LD1125H Mov 0m-2.8m"
|
||||
id: LD1125H_mth1_mov
|
||||
icon: mdi:cogs
|
||||
entity_category: "config"
|
||||
optimistic: true
|
||||
restore_value: true
|
||||
initial_value: "80"
|
||||
min_value: 0
|
||||
max_value: 1500
|
||||
step: 1
|
||||
set_action:
|
||||
then:
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string mth1_mov_st = "mth1_mov=" + str_sprintf("%.0f",x) +"\r\n";
|
||||
return std::vector<uint8_t>(mth1_mov_st.begin(), mth1_mov_st.end());
|
||||
|
||||
- platform: template
|
||||
name: "LD1125H Mov 2.8m-8m"
|
||||
id: LD1125H_mth2_mov
|
||||
icon: mdi:cogs
|
||||
entity_category: "config"
|
||||
optimistic: true
|
||||
restore_value: true
|
||||
initial_value: "50"
|
||||
min_value: 0
|
||||
max_value: 1500
|
||||
step: 1
|
||||
set_action:
|
||||
then:
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string mth2_mov_st = "mth2_mov=" + str_sprintf("%.0f",x) +"\r\n";
|
||||
return std::vector<uint8_t>(mth2_mov_st.begin(), mth2_mov_st.end());
|
||||
|
||||
- platform: template
|
||||
name: "LD1125H Mov 8m-∞m"
|
||||
id: LD1125H_mth3_mov
|
||||
icon: mdi:cogs
|
||||
entity_category: "config"
|
||||
optimistic: true
|
||||
restore_value: true
|
||||
initial_value: "80"
|
||||
min_value: 0
|
||||
max_value: 1500
|
||||
step: 1
|
||||
set_action:
|
||||
then:
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string mth3_mov_st = "mth3_mov=" + str_sprintf("%.0f",x) +"\r\n";
|
||||
return std::vector<uint8_t>(mth3_mov_st.begin(), mth3_mov_st.end());
|
||||
|
||||
- platform: template
|
||||
name: "LD1125H Occ 0m-2.8m"
|
||||
id: LD1125H_mth1_occ
|
||||
icon: mdi:cogs
|
||||
entity_category: "config"
|
||||
optimistic: true
|
||||
restore_value: true
|
||||
initial_value: "80"
|
||||
min_value: 0
|
||||
max_value: 1500
|
||||
step: 1
|
||||
set_action:
|
||||
then:
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string mth1_occ_st = "mth1_mov=" + str_sprintf("%.0f",x) +"\r\n";
|
||||
return std::vector<uint8_t>(mth1_occ_st.begin(), mth1_occ_st.end());
|
||||
|
||||
- platform: template
|
||||
name: "LD1125H Occ 2.8m-8m"
|
||||
id: LD1125H_mth2_occ
|
||||
icon: mdi:cogs
|
||||
entity_category: "config"
|
||||
optimistic: true
|
||||
restore_value: true
|
||||
initial_value: "50"
|
||||
min_value: 0
|
||||
max_value: 1500
|
||||
step: 1
|
||||
set_action:
|
||||
then:
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string mth2_occ_st = "mth2_occ=" + str_sprintf("%.0f",x) +"\r\n";
|
||||
return std::vector<uint8_t>(mth2_occ_st.begin(), mth2_occ_st.end());
|
||||
|
||||
- platform: template
|
||||
name: "LD1125H Occ 8m-∞m"
|
||||
id: LD1125H_mth3_occ
|
||||
icon: mdi:cogs
|
||||
entity_category: "config"
|
||||
optimistic: true
|
||||
restore_value: true
|
||||
initial_value: "80"
|
||||
min_value: 0
|
||||
max_value: 1500
|
||||
step: 1
|
||||
set_action:
|
||||
then:
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string mth3_occ_st = "mth3_occ=" + str_sprintf("%.0f",x) +"\r\n";
|
||||
return std::vector<uint8_t>(mth3_occ_st.begin(), mth3_occ_st.end());
|
||||
|
||||
- platform: template
|
||||
name: "LD1125H Max Dist (m)"
|
||||
id: LD1125H_rmax
|
||||
icon: mdi:cogs
|
||||
entity_category: "config"
|
||||
optimistic: true
|
||||
restore_value: true
|
||||
initial_value: "4"
|
||||
min_value: 0.0
|
||||
max_value: 20
|
||||
step: 0.1
|
||||
set_action:
|
||||
then:
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string rmaxst = "rmax=" + str_sprintf("%.1f",x) +"\r\n";
|
||||
return std::vector<uint8_t>(rmaxst.begin(), rmaxst.end());
|
||||
|
||||
- platform: template
|
||||
name: "LD1125H Clear Time"
|
||||
id: LD1125H_Clearance_Time
|
||||
icon: mdi:cogs
|
||||
entity_category: "config"
|
||||
optimistic: true
|
||||
restore_value: true
|
||||
initial_value: "15"
|
||||
min_value: 0
|
||||
max_value: 60
|
||||
step: 1
|
||||
|
||||
- platform: template
|
||||
name: "LD1125H Detect Time"
|
||||
id: LD1125H_Mov_Time
|
||||
icon: mdi:cogs
|
||||
entity_category: "config"
|
||||
optimistic: true
|
||||
restore_value: true
|
||||
initial_value: "0.1"
|
||||
min_value: 0.1
|
||||
max_value: 10
|
||||
step: 0.1
|
||||
|
||||
#
|
||||
# Radar Clear Scan Time Interval
|
||||
#
|
||||
interval:
|
||||
- interval: 1s
|
||||
then:
|
||||
lambda: |-
|
||||
if ((time(NULL)-id(LD1125H_Last_Time))>id(LD1125H_Clearance_Time).state) {
|
||||
if ((id(LD1125H_Clearance_Status) == false) || (id(LD1125H_Occupancy).state != "Clear")) {
|
||||
id(LD1125H_Occupancy).publish_state("Clear");
|
||||
id(LD1125H_Clearance_Status) = true;
|
||||
}
|
||||
if (id(LD1125H_MovOcc_Binary).state == true) {
|
||||
id(LD1125H_MovOcc_Binary).publish_state(false);
|
||||
}
|
||||
if (id(LD1125H_Mov_Binary).state == true) {
|
||||
id(LD1125H_Mov_Binary).publish_state(false);
|
||||
}
|
||||
}
|
@@ -1,480 +0,0 @@
|
||||
---
|
||||
|
||||
###############################################################################
|
||||
# SuperSensor v1.0 ESPHome configuration
|
||||
###############################################################################
|
||||
#
|
||||
# Copyright (C) 2023 Joshua M. Boniface <joshua@boniface.me>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
substitutions:
|
||||
# How long a PIR activation should be held for
|
||||
pir_holdtime: "15s"
|
||||
|
||||
esphome:
|
||||
name: supersensor
|
||||
name_add_mac_suffix: true
|
||||
friendly_name: "Supersensor"
|
||||
project:
|
||||
name: joshuaboniface.supersensor
|
||||
version: "0.1"
|
||||
# includes:
|
||||
# - veml7700.h
|
||||
# libraries:
|
||||
# - "Wire"
|
||||
# - "Adafruit Unified Sensor"
|
||||
# - "SPI"
|
||||
# - "Adafruit BusIO"
|
||||
# - "Adafruit VEML7700 Library"
|
||||
on_boot:
|
||||
- priority: 600
|
||||
then:
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
effect: flash
|
||||
red: 1
|
||||
green: 1
|
||||
blue: 1
|
||||
|
||||
dashboard_import:
|
||||
package_import_url: github://joshuaboniface/supersensor/supersensor.yaml
|
||||
import_full_config: false
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
# framework:
|
||||
# type: esp-idf
|
||||
# sdkconfig_options:
|
||||
# CONFIG_ESP32_DEFAULT_CPU_FREQ_240: "y"
|
||||
# CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ: "240"
|
||||
# CONFIG_ESP32_DATA_CACHE_64KB: "y"
|
||||
# CONFIG_ESP32_DATA_CACHE_LINE_64B: "y"
|
||||
# CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: "y"
|
||||
# CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ: "240"
|
||||
# CONFIG_ESP32S3_DATA_CACHE_64KB: "y"
|
||||
# CONFIG_ESP32S3_DATA_CACHE_LINE_64B: "y"
|
||||
|
||||
script:
|
||||
- id: pir_handler
|
||||
then:
|
||||
- lambda: |-
|
||||
id(pir_motion).publish_state(true);
|
||||
- while:
|
||||
condition:
|
||||
binary_sensor.is_on: pir_gpio
|
||||
then:
|
||||
- delay: ${pir_holdtime}
|
||||
- lambda: |-
|
||||
id(pir_motion).publish_state(false);
|
||||
|
||||
# Enable logging only via web
|
||||
logger:
|
||||
level: DEBUG
|
||||
baud_rate: 115200
|
||||
|
||||
api:
|
||||
encryption:
|
||||
key: !secret api_encryption_key
|
||||
on_client_disconnected:
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
effect: flash
|
||||
red: 1
|
||||
green: 1
|
||||
blue: 1
|
||||
- switch.turn_off: use_wake_word
|
||||
on_client_connected:
|
||||
- switch.turn_on: use_wake_word
|
||||
- delay: 2s
|
||||
- switch.turn_off: use_wake_word
|
||||
- delay: 2s
|
||||
- switch.turn_on: use_wake_word
|
||||
- delay: 2s
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
|
||||
ota:
|
||||
password: !secret ota_password
|
||||
safe_mode: false
|
||||
|
||||
web_server:
|
||||
port: 80
|
||||
auth:
|
||||
username: !secret web_auth_username
|
||||
password: !secret web_auth_password
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
domain: !secret wifi_domain
|
||||
power_save_mode: LIGHT
|
||||
reboot_timeout: 5min
|
||||
|
||||
uart:
|
||||
id: ld2410_uart
|
||||
rx_pin: GPIO18
|
||||
tx_pin: GPIO19
|
||||
baud_rate: 256000
|
||||
data_bits: 8
|
||||
stop_bits: 1
|
||||
parity: NONE
|
||||
|
||||
i2c:
|
||||
sda: GPIO16
|
||||
scl: GPIO17
|
||||
scan: true
|
||||
|
||||
i2s_audio:
|
||||
i2s_lrclk_pin: GPIO27
|
||||
i2s_bclk_pin: GPIO26
|
||||
|
||||
microphone:
|
||||
- platform: i2s_audio
|
||||
id: mic
|
||||
adc_type: external
|
||||
i2s_din_pin: GPIO14
|
||||
pdm: false
|
||||
|
||||
voice_assistant:
|
||||
microphone: mic
|
||||
use_wake_word: false
|
||||
noise_suppression_level: 2
|
||||
auto_gain: 31dBFS
|
||||
volume_multiplier: 4.0
|
||||
id: assist
|
||||
on_error:
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
transition_length: 1s
|
||||
- logger.log: "Voice Assistant encountered an error; restarting it"
|
||||
- switch.turn_off: use_wake_word
|
||||
- delay: 1s
|
||||
- switch.turn_on: use_wake_word
|
||||
on_wake_word_detected:
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
red: 0
|
||||
green: 0
|
||||
blue: 1
|
||||
on_listening:
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
red: 0
|
||||
green: 0
|
||||
blue: 1
|
||||
on_stt_end:
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
transition_length: 1s
|
||||
on_tts_start:
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
transition_length: 1s
|
||||
- if:
|
||||
condition:
|
||||
lambda: return x != "Sorry, I couldn't understand that";
|
||||
then:
|
||||
- logger.log: "Command successful!"
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
effect: hold
|
||||
red: 0
|
||||
green: 1
|
||||
blue: 0
|
||||
else:
|
||||
- logger.log: "Command failed!"
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
effect: hold
|
||||
red: 1
|
||||
green: 0
|
||||
blue: 0
|
||||
|
||||
light:
|
||||
- platform: rgb
|
||||
id: output_led
|
||||
red: rgb_r
|
||||
green: rgb_g
|
||||
blue: rgb_b
|
||||
default_transition_length: 0.15s
|
||||
flash_transition_length: 0.15s
|
||||
effects:
|
||||
- strobe:
|
||||
name: flash
|
||||
colors:
|
||||
- state: true
|
||||
duration: 0.5s
|
||||
- state: false
|
||||
duration: 0.5s
|
||||
- automation:
|
||||
name: hold
|
||||
sequence:
|
||||
- delay: 5s
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
transition_length: 1s
|
||||
|
||||
output:
|
||||
- platform: ledc
|
||||
id: rgb_r
|
||||
pin: GPIO32
|
||||
- platform: ledc
|
||||
id: rgb_g
|
||||
pin: GPIO33
|
||||
- platform: ledc
|
||||
id: rgb_b
|
||||
pin: GPIO25
|
||||
|
||||
ld2410:
|
||||
id: ld2410_radar
|
||||
uart_id: ld2410_uart
|
||||
# max_move_distance : 6m
|
||||
# max_still_distance: 0.75m
|
||||
# g0_move_threshold: 10
|
||||
# g0_still_threshold: 20
|
||||
# g1_move_threshold: 10
|
||||
# g1_still_threshold: 20
|
||||
# g2_move_threshold: 20
|
||||
# g2_still_threshold: 21
|
||||
# g3_move_threshold: 30
|
||||
# g3_still_threshold: 31
|
||||
# g4_move_threshold: 40
|
||||
# g4_still_threshold: 41
|
||||
# g5_move_threshold: 50
|
||||
# g5_still_threshold: 51
|
||||
# g6_move_threshold: 60
|
||||
# g6_still_threshold: 61
|
||||
# g7_move_threshold: 70
|
||||
# g7_still_threshold: 71
|
||||
# g8_move_threshold: 80
|
||||
# g8_still_threshold: 81
|
||||
|
||||
binary_sensor:
|
||||
- platform: gpio
|
||||
name: "PIR GPIO"
|
||||
id: pir_gpio
|
||||
pin: GPIO13
|
||||
internal: false
|
||||
device_class: motion
|
||||
on_press:
|
||||
- script.stop: pir_handler
|
||||
- script.execute: pir_handler
|
||||
|
||||
- platform: template
|
||||
name: "PIR Motion"
|
||||
id: pir_motion
|
||||
device_class: motion
|
||||
|
||||
- platform: ld2410
|
||||
ld2410_id: ld2410_radar
|
||||
has_target:
|
||||
name: "LD2410C Presence"
|
||||
has_moving_target:
|
||||
name: "LD2410C Moving Target"
|
||||
has_still_target:
|
||||
name: "LD2410C Still Target"
|
||||
|
||||
sensor:
|
||||
# - platform: bme280
|
||||
# temperature:
|
||||
# name: "BME280 Temperature"
|
||||
# pressure:
|
||||
# name: "BME280 Pressure"
|
||||
# humidity:
|
||||
# name: "BME280 Humidity"
|
||||
# update_interval: 15s
|
||||
# address: 0x76
|
||||
|
||||
- platform: bmp280
|
||||
temperature:
|
||||
name: "BMP280 Temperature"
|
||||
pressure:
|
||||
name: "BMP280 Pressure"
|
||||
update_interval: 5s
|
||||
address: 0x76
|
||||
|
||||
# - platform: custom
|
||||
# lambda: |-
|
||||
# auto veml7700 = new VEML7700CustomSensor();
|
||||
# App.register_component(veml7700);
|
||||
# return {veml7700->lux_sensor};
|
||||
# sensors:
|
||||
# - name: "VEML7700 Illumination"
|
||||
# unit_of_measurement: Lux
|
||||
# accuracy_decimals: 0
|
||||
|
||||
- platform: ld2410
|
||||
ld2410_id: ld2410_radar
|
||||
moving_distance:
|
||||
name: "LD2410C Moving Distance"
|
||||
id: moving_distance
|
||||
still_distance:
|
||||
name: "LD2410C Still Distance"
|
||||
id: still_distance
|
||||
moving_energy:
|
||||
name: "LD2410C Move Energy"
|
||||
still_energy:
|
||||
name: "LD2410C Still Energy"
|
||||
detection_distance:
|
||||
name: "LD2410C Presence Distance"
|
||||
|
||||
- platform: uptime
|
||||
name: "ESP32 Uptime"
|
||||
icon: mdi:clock-alert
|
||||
update_interval: 5s
|
||||
entity_category: diagnostic
|
||||
|
||||
- platform: wifi_signal
|
||||
name: "ESP32 WiFi RSSI"
|
||||
icon: mdi:wifi-strength-2
|
||||
update_interval: 5s
|
||||
entity_category: diagnostic
|
||||
|
||||
- platform: internal_temperature
|
||||
name: "ESP32 Temperature"
|
||||
icon: mdi:thermometer
|
||||
unit_of_measurement: °C
|
||||
device_class: TEMPERATURE
|
||||
update_interval: 5s
|
||||
entity_category: diagnostic
|
||||
|
||||
- platform: template
|
||||
name: "ESP32 CPU Frequency"
|
||||
icon: mdi:cpu-32-bit
|
||||
accuracy_decimals: 1
|
||||
unit_of_measurement: MHz
|
||||
update_interval: 5s
|
||||
lambda: |-
|
||||
return ets_get_cpu_frequency();
|
||||
entity_category: diagnostic
|
||||
|
||||
- platform: template
|
||||
name: "ESP32 Free Memory"
|
||||
icon: mdi:memory
|
||||
unit_of_measurement: 'kB'
|
||||
state_class: measurement
|
||||
update_interval: 5s
|
||||
lambda: |-
|
||||
return heap_caps_get_free_size(MALLOC_CAP_INTERNAL) / 1024;
|
||||
entity_category: diagnostic
|
||||
|
||||
text_sensor:
|
||||
- platform: ld2410
|
||||
version:
|
||||
name: "LD2410C Firmware Version"
|
||||
mac_address:
|
||||
name: "LD2410C MAC Address"
|
||||
|
||||
button:
|
||||
- platform: ld2410
|
||||
restart:
|
||||
name: "LD2410C Restart"
|
||||
factory_reset:
|
||||
name: "LD2410C Factory Reset"
|
||||
|
||||
- platform: restart
|
||||
name: "ESP32 Restart"
|
||||
icon: mdi:power-cycle
|
||||
entity_category: diagnostic
|
||||
|
||||
switch:
|
||||
- platform: template
|
||||
name: "Enable Wake Word"
|
||||
icon: mdi:account-voice
|
||||
id: use_wake_word
|
||||
optimistic: true
|
||||
restore_mode: ALWAYS_OFF
|
||||
entity_category: config
|
||||
on_turn_on:
|
||||
- lambda: id(assist).set_use_wake_word(true);
|
||||
- if:
|
||||
condition:
|
||||
not:
|
||||
- voice_assistant.is_running
|
||||
then:
|
||||
- voice_assistant.start_continuous
|
||||
on_turn_off:
|
||||
- voice_assistant.stop
|
||||
- lambda: id(assist).set_use_wake_word(false);
|
||||
|
||||
- platform: ld2410
|
||||
engineering_mode:
|
||||
name: "LD2410C Engineering Mode"
|
||||
bluetooth:
|
||||
name: "LD2410C Bluetooth"
|
||||
|
||||
number:
|
||||
- platform: ld2410
|
||||
timeout:
|
||||
name: "LD2410C Timeout"
|
||||
light_threshold:
|
||||
name: "LD2410C Light Threshold"
|
||||
max_move_distance_gate:
|
||||
name: "LD2410C Max Move Distance Gate"
|
||||
max_still_distance_gate:
|
||||
name: "LD2410C Max Still Distance Gate"
|
||||
g0:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate0 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate0 Still Threshold"
|
||||
g1:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate1 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate1 Still Threshold"
|
||||
g2:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate2 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate2 Still Threshold"
|
||||
g3:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate3 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate3 Still Threshold"
|
||||
g4:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate4 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate4 Still Threshold"
|
||||
g5:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate5 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate5 Still Threshold"
|
||||
g6:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate6 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate6 Still Threshold"
|
||||
g7:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate7 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate7 Still Threshold"
|
||||
g8:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate8 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate8 Still Threshold"
|
||||
|
||||
select:
|
||||
- platform: ld2410
|
||||
distance_resolution:
|
||||
name: "LD2410C Distance Resolution"
|
@@ -1,365 +0,0 @@
|
||||
substitutions:
|
||||
devicename: "supersensor" #Rename the device what you want.
|
||||
upper_devicename: ESP Radar #Rename the device what you want.
|
||||
entity_name_prefix: ""
|
||||
ignored_radar_ranges: |-
|
||||
{
|
||||
{2.20,3.30},
|
||||
{2.20,2.75}
|
||||
}
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
framework:
|
||||
type: esp-idf
|
||||
sdkconfig_options:
|
||||
CONFIG_ESP32_DEFAULT_CPU_FREQ_240: "y"
|
||||
CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ: "240"
|
||||
CONFIG_ESP32_DATA_CACHE_64KB: "y"
|
||||
CONFIG_ESP32_DATA_CACHE_LINE_64B: "y"
|
||||
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: "y"
|
||||
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ: "240"
|
||||
CONFIG_ESP32S3_DATA_CACHE_64KB: "y"
|
||||
CONFIG_ESP32S3_DATA_CACHE_LINE_64B: "y"
|
||||
|
||||
api:
|
||||
encryption:
|
||||
key: !secret api_encryption_key
|
||||
|
||||
ota:
|
||||
password: !secret ota_password
|
||||
|
||||
web_server:
|
||||
port: 80
|
||||
auth:
|
||||
username: !secret web_auth_username
|
||||
password: !secret web_auth_password
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
domain: !secret wifi_domain
|
||||
power_save_mode: LIGHT
|
||||
reboot_timeout: 5min
|
||||
|
||||
logger:
|
||||
level: DEBUG
|
||||
baud_rate: 115200
|
||||
logs:
|
||||
text_sensor: INFO
|
||||
|
||||
esphome:
|
||||
name: supersensor
|
||||
name_add_mac_suffix: false
|
||||
on_boot:
|
||||
priority: 200
|
||||
then:
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string mth1_mov_st = "mth1_mov=" + str_sprintf("%.0f",id(LD1125H_mth1_mov).state) +"\r\n";
|
||||
return std::vector<uint8_t>(mth1_mov_st.begin(), mth1_mov_st.end());
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string mth2_mov_st = "mth2_mov=" + str_sprintf("%.0f",id(LD1125H_mth2_mov).state) +"\r\n";
|
||||
return std::vector<uint8_t>(mth2_mov_st.begin(), mth2_mov_st.end());
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string mth3_mov_st = "mth3_mov=" + str_sprintf("%.0f",id(LD1125H_mth3_mov).state) +"\r\n";
|
||||
return std::vector<uint8_t>(mth3_mov_st.begin(), mth3_mov_st.end());
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string mth1_occ_st = "mth1_occ=" + str_sprintf("%.0f",id(LD1125H_mth1_occ).state) +"\r\n";
|
||||
return std::vector<uint8_t>(mth1_occ_st.begin(), mth1_occ_st.end());
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string mth2_occ_st = "mth2_occ=" + str_sprintf("%.0f",id(LD1125H_mth2_occ).state) +"\r\n";
|
||||
return std::vector<uint8_t>(mth2_occ_st.begin(), mth2_occ_st.end());
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string mth3_occ_st = "mth3_occ=" + str_sprintf("%.0f",id(LD1125H_mth3_occ).state) +"\r\n";
|
||||
return std::vector<uint8_t>(mth3_occ_st.begin(), mth3_occ_st.end());
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string rmaxst = "rmax=" + str_sprintf("%.1f",id(LD1125H_rmax).state) +"\r\n";
|
||||
return std::vector<uint8_t>(rmaxst.begin(), rmaxst.end());
|
||||
|
||||
external_components:
|
||||
- source:
|
||||
type: git
|
||||
url: https://github.com/ssieb/custom_components #Thanks for @ssieb components.
|
||||
components: [ serial ]
|
||||
|
||||
uart:
|
||||
id: LD1125H_UART_BUS
|
||||
rx_pin: GPIO16
|
||||
tx_pin: GPIO17
|
||||
baud_rate: 115200
|
||||
data_bits: 8
|
||||
stop_bits: 1
|
||||
parity: NONE
|
||||
# debug:
|
||||
# direction: BOTH
|
||||
# dummy_receiver: false
|
||||
# after:
|
||||
# delimiter: "\n"
|
||||
# sequence:
|
||||
# - lambda: UARTDebug::log_string(direction, bytes);
|
||||
status_led:
|
||||
pin:
|
||||
number: GPIO2
|
||||
inverted: false
|
||||
globals:
|
||||
- id: LD1125H_Last_Time
|
||||
type: time_t
|
||||
restore_value: no
|
||||
initial_value: time(NULL)
|
||||
- id: LD1125H_Last_Mov_Time
|
||||
type: time_t
|
||||
restore_value: no
|
||||
initial_value: time(NULL)
|
||||
- id: LD1125H_Clearance_Status
|
||||
type: bool
|
||||
restore_value: no
|
||||
initial_value: "false"
|
||||
- id: ignored_ranges
|
||||
type: std::vector<std::vector<float>>
|
||||
restore_value: no
|
||||
initial_value: ${ignored_radar_ranges}
|
||||
interval:
|
||||
- interval: 1s #Clearance Scan Time
|
||||
setup_priority: 200
|
||||
then:
|
||||
lambda: |-
|
||||
if ((time(NULL)-id(LD1125H_Last_Time))>id(LD1125H_Clearance_Time).state) {
|
||||
if ((id(LD1125H_Clearance_Status) == false) || (id(LD1125H_Occupancy).state != "Clear")) {
|
||||
id(LD1125H_Occupancy).publish_state("Clear");
|
||||
id(LD1125H_Clearance_Status) = true;
|
||||
}
|
||||
if (id(LD1125H_MovOcc_Binary).state == true) {
|
||||
id(LD1125H_MovOcc_Binary).publish_state(false);
|
||||
}
|
||||
if (id(LD1125H_Mov_Binary).state == true) {
|
||||
id(LD1125H_Mov_Binary).publish_state(false);
|
||||
}
|
||||
}
|
||||
number:
|
||||
- platform: template
|
||||
name: ${entity_name_prefix} 0-2.8m Movement Minimum Signal
|
||||
id: LD1125H_mth1_mov
|
||||
icon: "mdi:cogs"
|
||||
optimistic: true
|
||||
restore_value: true
|
||||
initial_value: "80"
|
||||
min_value: 0
|
||||
max_value: 1500
|
||||
step: 1
|
||||
set_action:
|
||||
then:
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string mth1_mov_st = "mth1_mov=" + str_sprintf("%.0f",x) +"\r\n";
|
||||
return std::vector<uint8_t>(mth1_mov_st.begin(), mth1_mov_st.end());
|
||||
- platform: template
|
||||
name: ${entity_name_prefix} 2.8m-8m Movement Minimum Signal
|
||||
id: LD1125H_mth2_mov
|
||||
icon: "mdi:cogs"
|
||||
optimistic: true
|
||||
restore_value: true #If you don't want to store the setting at ESP, set it to false.
|
||||
initial_value: "50"
|
||||
min_value: 0
|
||||
max_value: 1500
|
||||
step: 1
|
||||
set_action:
|
||||
then:
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string mth2_mov_st = "mth2_mov=" + str_sprintf("%.0f",x) +"\r\n";
|
||||
return std::vector<uint8_t>(mth2_mov_st.begin(), mth2_mov_st.end());
|
||||
- platform: template
|
||||
name: ${entity_name_prefix} 8m-∞ Movement Minimum Signal
|
||||
id: LD1125H_mth3_mov
|
||||
icon: "mdi:cogs"
|
||||
optimistic: true
|
||||
restore_value: true #If you don't want to store the setting at ESP, set it to false.
|
||||
initial_value: "20"
|
||||
min_value: 0
|
||||
max_value: 1500
|
||||
step: 1
|
||||
set_action:
|
||||
then:
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string mth3_mov_st = "mth3_mov=" + str_sprintf("%.0f",x) +"\r\n";
|
||||
return std::vector<uint8_t>(mth3_mov_st.begin(), mth3_mov_st.end());
|
||||
- platform: template
|
||||
name: ${entity_name_prefix} 0-2.8m Occupancy Minimum Signal
|
||||
id: LD1125H_mth1_occ
|
||||
icon: "mdi:cogs"
|
||||
optimistic: true
|
||||
restore_value: true
|
||||
initial_value: "60"
|
||||
min_value: 0
|
||||
max_value: 1500
|
||||
step: 1
|
||||
set_action:
|
||||
then:
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string mth1_occ_st = "mth1_occ=" + str_sprintf("%.0f",x) +"\r\n";
|
||||
return std::vector<uint8_t>(mth1_occ_st.begin(), mth1_occ_st.end());
|
||||
- platform: template
|
||||
name: ${entity_name_prefix} 2.8m-8m Occupancy Minimum Signal
|
||||
id: LD1125H_mth2_occ
|
||||
icon: "mdi:cogs"
|
||||
optimistic: true
|
||||
restore_value: true #If you don't want to store the setting at ESP, set it to false.
|
||||
initial_value: "55"
|
||||
min_value: 0
|
||||
max_value: 1500
|
||||
step: 1
|
||||
set_action:
|
||||
then:
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string mth2_occ_st = "mth2_occ=" + str_sprintf("%.0f",x) +"\r\n";
|
||||
return std::vector<uint8_t>(mth2_occ_st.begin(), mth2_occ_st.end());
|
||||
- platform: template
|
||||
name: ${entity_name_prefix} 8m-∞ Occupancy Minimum Signal
|
||||
id: LD1125H_mth3_occ
|
||||
icon: "mdi:cogs"
|
||||
optimistic: true
|
||||
restore_value: true #If you don't want to store the setting at ESP, set it to false.
|
||||
initial_value: "20"
|
||||
min_value: 0
|
||||
max_value: 1500
|
||||
step: 1
|
||||
set_action:
|
||||
then:
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string mth3_occ_st = "mth3_occ=" + str_sprintf("%.0f",x) +"\r\n";
|
||||
return std::vector<uint8_t>(mth3_occ_st.begin(), mth3_occ_st.end());
|
||||
- platform: template
|
||||
name: ${entity_name_prefix} Max Detection Distance (m) #rmax is max detection distance.
|
||||
id: LD1125H_rmax
|
||||
icon: "mdi:cogs"
|
||||
optimistic: true
|
||||
restore_value: true #If you don't want to store the setting at ESP, set it to false.
|
||||
initial_value: "8" #Default rmax Setting
|
||||
min_value: 0.0
|
||||
max_value: 60
|
||||
step: 0.1
|
||||
set_action:
|
||||
then:
|
||||
- uart.write:
|
||||
id: LD1125H_UART_BUS
|
||||
data: !lambda |-
|
||||
std::string rmaxst = "rmax=" + str_sprintf("%.1f",x) +"\r\n";
|
||||
return std::vector<uint8_t>(rmaxst.begin(), rmaxst.end());
|
||||
- platform: template
|
||||
name: ${entity_name_prefix} Seconds to Clear Mov/Occ
|
||||
id: LD1125H_Clearance_Time
|
||||
icon: "mdi:cogs"
|
||||
optimistic: true
|
||||
restore_value: true #If you don't want to store the setting at ESP, set it to false.
|
||||
initial_value: "20" #LD1125H Mov/Occ > Clearance Time Here
|
||||
min_value: 0
|
||||
max_value: 60
|
||||
step: 1
|
||||
- platform: template
|
||||
name: ${entity_name_prefix} Seconds to Detection
|
||||
id: LD1125H_Mov_Time
|
||||
icon: "mdi:cogs"
|
||||
optimistic: true
|
||||
restore_value: true #If you don't want to store the setting at ESP, set it to false.
|
||||
initial_value: "1" #LD1125H Mov > Occ Time Here
|
||||
min_value: 0.1
|
||||
max_value: 10
|
||||
step: 0.1
|
||||
sensor:
|
||||
- platform: template
|
||||
name: ${entity_name_prefix} Objects Distance
|
||||
id: LD1125H_Distance
|
||||
icon: "mdi:signal-distance-variant"
|
||||
unit_of_measurement: "m"
|
||||
accuracy_decimals: 2
|
||||
filters: # Use Filter To Debounce
|
||||
- sliding_window_moving_average:
|
||||
window_size: 200
|
||||
send_every: 10
|
||||
- heartbeat: 0.2s
|
||||
text_sensor:
|
||||
- platform: serial
|
||||
uart_id: LD1125H_UART_BUS
|
||||
name: ${entity_name_prefix} UART Text
|
||||
id: LD1125H_UART_Text
|
||||
icon: "mdi:format-text"
|
||||
internal: True
|
||||
on_value:
|
||||
lambda: |-
|
||||
for (const auto& row : id(ignored_ranges)) {
|
||||
if ( ( atof(id(LD1125H_UART_Text).state.substr(9).c_str()) > row[0] ) && ( atof(id(LD1125H_UART_Text).state.substr(9).c_str()) < row[1] ) ) {
|
||||
break;
|
||||
} else {
|
||||
if (id(LD1125H_UART_Text).state.substr(0,3) == "occ") {
|
||||
id(LD1125H_Distance).publish_state(atof(id(LD1125H_UART_Text).state.substr(9).c_str()));
|
||||
if ((time(NULL)-id(LD1125H_Last_Mov_Time))>id(LD1125H_Mov_Time).state) {
|
||||
id(LD1125H_Occupancy).publish_state("Occupied");
|
||||
if (id(LD1125H_MovOcc_Binary).state == false) {
|
||||
id(LD1125H_MovOcc_Binary).publish_state(true);
|
||||
}
|
||||
if (id(LD1125H_Mov_Binary).state == true) {
|
||||
id(LD1125H_Mov_Binary).publish_state(false);
|
||||
}
|
||||
}
|
||||
if (id(LD1125H_MovOcc_Binary).state == false) {
|
||||
id(LD1125H_MovOcc_Binary).publish_state(true);
|
||||
}
|
||||
id(LD1125H_Last_Time) = time(NULL);
|
||||
if (id(LD1125H_Clearance_Status) == true) {
|
||||
id(LD1125H_Clearance_Status) = false;
|
||||
}
|
||||
}
|
||||
else if (id(LD1125H_UART_Text).state.substr(0,3) == "mov") {
|
||||
id(LD1125H_Distance).publish_state(atof(id(LD1125H_UART_Text).state.substr(9).c_str()));
|
||||
id(LD1125H_Occupancy).publish_state("Movement");
|
||||
if (id(LD1125H_MovOcc_Binary).state == false) {
|
||||
id(LD1125H_MovOcc_Binary).publish_state(true);
|
||||
}
|
||||
if (id(LD1125H_Mov_Binary).state == false) {
|
||||
id(LD1125H_Mov_Binary).publish_state(true);
|
||||
}
|
||||
id(LD1125H_Last_Mov_Time) = time(NULL);
|
||||
id(LD1125H_Last_Time) = time(NULL);
|
||||
if (id(LD1125H_Clearance_Status) == true) {
|
||||
id(LD1125H_Clearance_Status) = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
- platform: template
|
||||
name: ${entity_name_prefix} Occupancy Status
|
||||
id: LD1125H_Occupancy
|
||||
icon: "mdi:motion-sensor"
|
||||
binary_sensor:
|
||||
- platform: template
|
||||
name: ${entity_name_prefix} Occupancy or Movement
|
||||
id: LD1125H_MovOcc_Binary
|
||||
device_class: occupancy
|
||||
- platform: template
|
||||
name: ${entity_name_prefix} Motion
|
||||
id: LD1125H_Mov_Binary
|
||||
device_class: motion
|
@@ -1,103 +0,0 @@
|
||||
|
||||
esphome:
|
||||
name: supersensor
|
||||
name_add_mac_suffix: true
|
||||
friendly_name: "Supersensor"
|
||||
project:
|
||||
name: joshuaboniface.supersensor
|
||||
version: "0.1"
|
||||
|
||||
logger:
|
||||
level: DEBUG
|
||||
baud_rate: 115200
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
framework:
|
||||
type: esp-idf
|
||||
sdkconfig_options:
|
||||
CONFIG_ESP32_DEFAULT_CPU_FREQ_240: "y"
|
||||
CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ: "240"
|
||||
CONFIG_ESP32_DATA_CACHE_64KB: "y"
|
||||
CONFIG_ESP32_DATA_CACHE_LINE_64B: "y"
|
||||
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: "y"
|
||||
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ: "240"
|
||||
CONFIG_ESP32S3_DATA_CACHE_64KB: "y"
|
||||
CONFIG_ESP32S3_DATA_CACHE_LINE_64B: "y"
|
||||
|
||||
script:
|
||||
- id: ledtest
|
||||
then:
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
effect: flash_white
|
||||
- delay: 5s
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
- delay: 5s
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
red: 1
|
||||
green: 0
|
||||
blue: 0
|
||||
- delay: 5s
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
red: 0
|
||||
green: 1
|
||||
blue: 0
|
||||
- delay: 5s
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
red: 0
|
||||
green: 0
|
||||
blue: 1
|
||||
|
||||
interval:
|
||||
- interval: 30s
|
||||
then:
|
||||
- script.stop: ledtest
|
||||
- light.turn_off: output_led
|
||||
- script.execute: ledtest
|
||||
|
||||
light:
|
||||
- platform: rgb
|
||||
id: output_led
|
||||
red: rgb_r
|
||||
green: rgb_g
|
||||
blue: rgb_b
|
||||
default_transition_length: 0.15s
|
||||
flash_transition_length: 0.15s
|
||||
effects:
|
||||
- strobe:
|
||||
name: flash_white
|
||||
colors:
|
||||
- state: true
|
||||
brightness: 50%
|
||||
red: 40%
|
||||
green: 50%
|
||||
blue: 45%
|
||||
duration: 0.5s
|
||||
- state: false
|
||||
duration: 0.5s
|
||||
- automation:
|
||||
name: hold
|
||||
sequence:
|
||||
- delay: 5s
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
transition_length: 1s
|
||||
|
||||
output:
|
||||
- platform: ledc
|
||||
id: rgb_r
|
||||
pin: GPIO32
|
||||
max_power: 100%
|
||||
- platform: ledc
|
||||
id: rgb_g
|
||||
pin: GPIO33
|
||||
max_power: 100%
|
||||
- platform: ledc
|
||||
id: rgb_b
|
||||
pin: GPIO25
|
||||
max_power: 100%
|
@@ -1,99 +0,0 @@
|
||||
---
|
||||
|
||||
###############################################################################
|
||||
# SuperSensor v1.0 ESPHome configuration
|
||||
###############################################################################
|
||||
#
|
||||
# Copyright (C) 2023 Joshua M. Boniface <joshua@boniface.me>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
esphome:
|
||||
name: pirtester
|
||||
friendly_name: "PIRTester"
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
framework:
|
||||
type: esp-idf
|
||||
sdkconfig_options:
|
||||
CONFIG_ESP32_DEFAULT_CPU_FREQ_240: "y"
|
||||
CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ: "240"
|
||||
CONFIG_ESP32_DATA_CACHE_64KB: "y"
|
||||
CONFIG_ESP32_DATA_CACHE_LINE_64B: "y"
|
||||
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: "y"
|
||||
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ: "240"
|
||||
CONFIG_ESP32S3_DATA_CACHE_64KB: "y"
|
||||
CONFIG_ESP32S3_DATA_CACHE_LINE_64B: "y"
|
||||
|
||||
# Enable logging only via web
|
||||
logger:
|
||||
level: DEBUG
|
||||
baud_rate: 115200
|
||||
|
||||
api:
|
||||
encryption:
|
||||
key: !secret api_encryption_key
|
||||
|
||||
ota:
|
||||
password: !secret ota_password
|
||||
safe_mode: false
|
||||
|
||||
web_server:
|
||||
port: 80
|
||||
auth:
|
||||
username: !secret web_auth_username
|
||||
password: !secret web_auth_password
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
domain: !secret wifi_domain
|
||||
power_save_mode: LIGHT
|
||||
reboot_timeout: 5min
|
||||
|
||||
binary_sensor:
|
||||
- platform: gpio
|
||||
pin: GPIO32
|
||||
name: "PIR 32"
|
||||
device_class: motion
|
||||
- platform: gpio
|
||||
pin: GPIO33
|
||||
name: "PIR 33"
|
||||
device_class: motion
|
||||
- platform: gpio
|
||||
pin: GPIO25
|
||||
name: "PIR 25"
|
||||
device_class: motion
|
||||
- platform: gpio
|
||||
pin: GPIO26
|
||||
name: "PIR 26"
|
||||
device_class: motion
|
||||
- platform: gpio
|
||||
pin: GPIO27
|
||||
name: "PIR 27"
|
||||
device_class: motion
|
||||
- platform: gpio
|
||||
pin: GPIO14
|
||||
name: "PIR 14"
|
||||
device_class: motion
|
||||
- platform: gpio
|
||||
pin: GPIO12
|
||||
name: "PIR 12"
|
||||
device_class: motion
|
||||
- platform: gpio
|
||||
pin: GPIO13
|
||||
name: "PIR 13"
|
||||
device_class: motion
|
@@ -1,866 +0,0 @@
|
||||
---
|
||||
|
||||
###############################################################################
|
||||
# SuperSensor v1.0 ESPHome configuration
|
||||
###############################################################################
|
||||
#
|
||||
# Copyright (C) 2023 Joshua M. Boniface <joshua@boniface.me>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
esphome:
|
||||
name: supersensor
|
||||
name_add_mac_suffix: true
|
||||
friendly_name: "Supersensor"
|
||||
project:
|
||||
name: joshuaboniface.supersensor
|
||||
version: "0.1"
|
||||
on_boot:
|
||||
- priority: 600
|
||||
then:
|
||||
- lambda: |-
|
||||
id(supersensor_occupancy).publish_state(false);
|
||||
id(pir_presence).publish_state(false);
|
||||
id(light_presence).publish_state(false);
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
effect: flash_white
|
||||
|
||||
dashboard_import:
|
||||
package_import_url: github://joshuaboniface/supersensor/supersensor.yaml
|
||||
import_full_config: false
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
|
||||
globals:
|
||||
- id: pir_hold_time
|
||||
type: int
|
||||
restore_value: yes
|
||||
initial_value: "15"
|
||||
|
||||
- id: light_presence_threshold
|
||||
type: int
|
||||
restore_value: yes
|
||||
initial_value: "30"
|
||||
|
||||
- id: occupancy_detect_mode
|
||||
type: int
|
||||
restore_value: yes
|
||||
initial_value: "0"
|
||||
|
||||
- id: occupancy_clear_mode
|
||||
type: int
|
||||
restore_value: yes
|
||||
initial_value: "0"
|
||||
|
||||
script:
|
||||
- id: pir_handler
|
||||
then:
|
||||
- lambda: |-
|
||||
id(pir_presence).publish_state(true);
|
||||
- while:
|
||||
condition:
|
||||
binary_sensor.is_on: pir_gpio
|
||||
then:
|
||||
- delay: !lambda 'return(id(pir_hold_time) * 1000);'
|
||||
- lambda: |-
|
||||
id(pir_presence).publish_state(false);
|
||||
|
||||
- id: light_handler
|
||||
then:
|
||||
- lambda: |-
|
||||
if (id(tsl2591_lux).state >= id(light_presence_threshold)) {
|
||||
id(light_presence).publish_state(true);
|
||||
} else {
|
||||
id(light_presence).publish_state(false);
|
||||
}
|
||||
|
||||
- id: occupancy_detect_handler
|
||||
then:
|
||||
- lambda: |-
|
||||
ESP_LOGD("occupancy_detect_handler", "Occupancy detect handler triggered");
|
||||
|
||||
// Get the current values of our presence sensors
|
||||
bool pir = id(pir_presence).state;
|
||||
bool radar = id(radar_presence).state;
|
||||
bool light = id(light_presence).state;
|
||||
|
||||
// Determine if PIR counts (2nd bit of presence_type)
|
||||
int pir_counts = (id(occupancy_detect_mode) & ( 1 << 2 )) >> 2;
|
||||
|
||||
// Determine if Radar counts (1st bit of presence_type)
|
||||
int radar_counts = (id(occupancy_detect_mode) & ( 1 << 1 )) >> 1;
|
||||
|
||||
// Determine if Light counts (0th bit of presence_type)
|
||||
int light_counts = (id(occupancy_detect_mode) & ( 1 << 0 )) >> 0;
|
||||
|
||||
// Determine our results
|
||||
if (pir_counts & radar_counts & light_counts) {
|
||||
// Logical AND of pir & radar & light
|
||||
ESP_LOGD("occupancy_detect_handler", "PIR & Radar & Light: %i", pir & radar & light);
|
||||
id(supersensor_occupancy).publish_state(pir & radar & light);
|
||||
} else if (pir_counts & radar_counts) {
|
||||
// Logical AND of pir & radar
|
||||
ESP_LOGD("occupancy_detect_handler", "PIR & Radar: %i", pir & radar);
|
||||
id(supersensor_occupancy).publish_state(pir & radar);
|
||||
} else if (pir_counts & light_counts) {
|
||||
// Logical AND of pir & light
|
||||
ESP_LOGD("occupancy_detect_handler", "PIR & Light: %i", pir & light);
|
||||
id(supersensor_occupancy).publish_state(pir & light);
|
||||
} else if (radar_counts & light_counts) {
|
||||
// Logical AND of radar & light
|
||||
ESP_LOGD("occupancy_detect_handler", "Radar & Light: %i", radar & light);
|
||||
id(supersensor_occupancy).publish_state(radar & light);
|
||||
} else if (pir_counts) {
|
||||
// Only pir
|
||||
ESP_LOGD("occupancy_detect_handler", "PIR: %i", pir);
|
||||
id(supersensor_occupancy).publish_state(pir);
|
||||
} else if (radar_counts) {
|
||||
// Only radar
|
||||
ESP_LOGD("occupancy_detect_handler", "Radar: %i", radar);
|
||||
id(supersensor_occupancy).publish_state(radar);
|
||||
} else if (light_counts) {
|
||||
// Only light
|
||||
ESP_LOGD("occupancy_detect_handler", "Light: %i", light);
|
||||
id(supersensor_occupancy).publish_state(light);
|
||||
} else {
|
||||
ESP_LOGD("occupancy_detect_handler", "None");
|
||||
id(supersensor_occupancy).publish_state(false);
|
||||
}
|
||||
|
||||
- id: occupancy_clear_handler
|
||||
then:
|
||||
- lambda: |-
|
||||
ESP_LOGD("occupancy_clear_handler", "Occupancy clear handler triggered");
|
||||
|
||||
// Get the current values of our presence sensors
|
||||
bool pir = id(pir_presence).state;
|
||||
bool radar = id(radar_presence).state;
|
||||
bool light = id(light_presence).state;
|
||||
|
||||
// Determine if PIR counts (2nd bit of presence_type)
|
||||
int pir_counts = (id(occupancy_clear_mode) & ( 1 << 2 )) >> 2;
|
||||
|
||||
// Determine if Radar counts (1st bit of presence_type)
|
||||
int radar_counts = (id(occupancy_clear_mode) & ( 1 << 1 )) >> 1;
|
||||
|
||||
// Determine if Light counts (0th bit of presence_type)
|
||||
int light_counts = (id(occupancy_clear_mode) & ( 1 << 0 )) >> 0;
|
||||
|
||||
// Determine our results
|
||||
if (pir_counts & radar_counts & light_counts) {
|
||||
// Logical AND of pir & radar & light
|
||||
ESP_LOGD("occupancy_clear_handler", "PIR & Radar & Light: %i", pir & radar & light);
|
||||
id(supersensor_occupancy).publish_state(pir & radar & light);
|
||||
} else if (pir_counts & radar_counts) {
|
||||
// Logical AND of pir & radar
|
||||
ESP_LOGD("occupancy_clear_handler", "PIR & Radar: %i", pir & radar);
|
||||
id(supersensor_occupancy).publish_state(pir & radar);
|
||||
} else if (pir_counts & light_counts) {
|
||||
// Logical AND of pir & light
|
||||
ESP_LOGD("occupancy_clear_handler", "PIR & Light: %i", pir & light);
|
||||
id(supersensor_occupancy).publish_state(pir & light);
|
||||
} else if (radar_counts & light_counts) {
|
||||
// Logical AND of radar & light
|
||||
ESP_LOGD("occupancy_clear_handler", "Radar & Light: %i", radar & light);
|
||||
id(supersensor_occupancy).publish_state(radar & light);
|
||||
} else if (pir_counts) {
|
||||
// Only pir
|
||||
ESP_LOGD("occupancy_clear_handler", "PIR: %i", pir);
|
||||
id(supersensor_occupancy).publish_state(pir);
|
||||
} else if (radar_counts) {
|
||||
// Only radar
|
||||
ESP_LOGD("occupancy_clear_handler", "Radar: %i", radar);
|
||||
id(supersensor_occupancy).publish_state(radar);
|
||||
} else if (light_counts) {
|
||||
// Only light
|
||||
ESP_LOGD("occupancy_clear_handler", "Light: %i", light);
|
||||
id(supersensor_occupancy).publish_state(light);
|
||||
} else {
|
||||
ESP_LOGD("occupancy_clear_handler", "None");
|
||||
id(supersensor_occupancy).publish_state(false);
|
||||
}
|
||||
|
||||
logger:
|
||||
level: DEBUG
|
||||
baud_rate: 115200
|
||||
|
||||
api:
|
||||
encryption:
|
||||
key: !secret api_encryption_key
|
||||
on_client_disconnected:
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
effect: flash_white
|
||||
- switch.turn_off: use_wake_word
|
||||
on_client_connected:
|
||||
# This absolute absurdity is required to prevent
|
||||
# "no wake word detected" failure loops.
|
||||
- switch.turn_on: use_wake_word
|
||||
- delay: 2s
|
||||
- switch.turn_off: use_wake_word
|
||||
- delay: 2s
|
||||
- switch.turn_on: use_wake_word
|
||||
- delay: 2s
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
|
||||
ota:
|
||||
password: !secret ota_password
|
||||
safe_mode: false
|
||||
|
||||
web_server:
|
||||
port: 80
|
||||
auth:
|
||||
username: !secret web_auth_username
|
||||
password: !secret web_auth_password
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
domain: !secret wifi_domain
|
||||
power_save_mode: LIGHT
|
||||
reboot_timeout: 5min
|
||||
|
||||
uart:
|
||||
id: ld2410_uart
|
||||
rx_pin: GPIO19
|
||||
tx_pin: GPIO18
|
||||
baud_rate: 256000
|
||||
data_bits: 8
|
||||
stop_bits: 1
|
||||
parity: NONE
|
||||
|
||||
i2c:
|
||||
sda: GPIO16
|
||||
scl: GPIO17
|
||||
scan: true
|
||||
|
||||
i2s_audio:
|
||||
i2s_lrclk_pin: GPIO26
|
||||
i2s_bclk_pin: GPIO27
|
||||
|
||||
microphone:
|
||||
- platform: i2s_audio
|
||||
id: mic
|
||||
adc_type: external
|
||||
i2s_din_pin: GPIO14
|
||||
pdm: false
|
||||
|
||||
voice_assistant:
|
||||
microphone: mic
|
||||
use_wake_word: false
|
||||
noise_suppression_level: 2
|
||||
auto_gain: 31dBFS
|
||||
volume_multiplier: 4.0
|
||||
id: assist
|
||||
on_error:
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
transition_length: 1s
|
||||
- logger.log: "Voice Assistant encountered an error; restarting it"
|
||||
- switch.turn_off: use_wake_word
|
||||
- delay: 1s
|
||||
- switch.turn_on: use_wake_word
|
||||
on_wake_word_detected:
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
red: 0
|
||||
green: 0
|
||||
blue: 1
|
||||
on_listening:
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
red: 0
|
||||
green: 0
|
||||
blue: 1
|
||||
on_stt_end:
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
transition_length: 1s
|
||||
on_tts_start:
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
transition_length: 1s
|
||||
- if:
|
||||
condition:
|
||||
lambda: return x != "Sorry, I couldn't understand that";
|
||||
then:
|
||||
- logger.log: "Command successful!"
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
effect: hold
|
||||
red: 0
|
||||
green: 1
|
||||
blue: 0
|
||||
else:
|
||||
- logger.log: "Command failed!"
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
effect: hold
|
||||
red: 1
|
||||
green: 0
|
||||
blue: 0
|
||||
|
||||
light:
|
||||
- platform: rgb
|
||||
id: output_led
|
||||
red: rgb_r
|
||||
green: rgb_g
|
||||
blue: rgb_b
|
||||
default_transition_length: 0.15s
|
||||
flash_transition_length: 0.15s
|
||||
effects:
|
||||
- strobe:
|
||||
name: flash_white
|
||||
colors:
|
||||
- state: true
|
||||
brightness: 50%
|
||||
red: 100%
|
||||
green: 100%
|
||||
blue: 100%
|
||||
duration: 0.5s
|
||||
- state: false
|
||||
duration: 0.5s
|
||||
- automation:
|
||||
name: hold
|
||||
sequence:
|
||||
- delay: 5s
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
transition_length: 1s
|
||||
|
||||
output:
|
||||
- platform: ledc
|
||||
id: rgb_r
|
||||
pin: GPIO32
|
||||
- platform: ledc
|
||||
id: rgb_g
|
||||
pin: GPIO33
|
||||
- platform: ledc
|
||||
id: rgb_b
|
||||
pin: GPIO25
|
||||
|
||||
bme680_bsec:
|
||||
address: 0x77
|
||||
id: bme680_sensor
|
||||
sample_rate: lp
|
||||
state_save_interval: 1h
|
||||
iaq_mode: static
|
||||
|
||||
ld2410:
|
||||
id: ld2410_radar
|
||||
uart_id: ld2410_uart
|
||||
# These default values are captured here for
|
||||
# posterity. They are configured below.
|
||||
# max_move_distance : 6m
|
||||
# max_still_distance: 0.75m
|
||||
# g0_move_threshold: 10
|
||||
# g0_still_threshold: 20
|
||||
# g1_move_threshold: 10
|
||||
# g1_still_threshold: 20
|
||||
# g2_move_threshold: 20
|
||||
# g2_still_threshold: 21
|
||||
# g3_move_threshold: 30
|
||||
# g3_still_threshold: 31
|
||||
# g4_move_threshold: 40
|
||||
# g4_still_threshold: 41
|
||||
# g5_move_threshold: 50
|
||||
# g5_still_threshold: 51
|
||||
# g6_move_threshold: 60
|
||||
# g6_still_threshold: 61
|
||||
# g7_move_threshold: 70
|
||||
# g7_still_threshold: 71
|
||||
# g8_move_threshold: 80
|
||||
# g8_still_threshold: 81
|
||||
|
||||
binary_sensor:
|
||||
- platform: template
|
||||
name: "SuperSensor Occupancy"
|
||||
id: supersensor_occupancy
|
||||
device_class: occupancy
|
||||
|
||||
- platform: gpio
|
||||
name: "PIR GPIO"
|
||||
id: pir_gpio
|
||||
pin: GPIO13
|
||||
internal: false
|
||||
device_class: motion
|
||||
on_press:
|
||||
- script.stop: pir_handler
|
||||
- script.execute: pir_handler
|
||||
|
||||
- platform: template
|
||||
name: "PIR Presence"
|
||||
id: pir_presence
|
||||
device_class: motion
|
||||
on_press:
|
||||
- script.execute: occupancy_detect_handler
|
||||
on_release:
|
||||
- script.execute: occupancy_clear_handler
|
||||
|
||||
- platform: template
|
||||
name: "Light Presence"
|
||||
id: light_presence
|
||||
device_class: motion
|
||||
on_press:
|
||||
- script.execute: occupancy_detect_handler
|
||||
on_release:
|
||||
- script.execute: occupancy_clear_handler
|
||||
|
||||
- platform: ld2410
|
||||
ld2410_id: ld2410_radar
|
||||
has_target:
|
||||
name: "LD2410C Presence"
|
||||
id: radar_presence
|
||||
device_class: motion
|
||||
on_press:
|
||||
- script.execute: occupancy_detect_handler
|
||||
on_release:
|
||||
- script.execute: occupancy_clear_handler
|
||||
has_moving_target:
|
||||
name: "LD2410C Moving Target"
|
||||
has_still_target:
|
||||
name: "LD2410C Still Target"
|
||||
|
||||
sensor:
|
||||
- platform: bme680_bsec
|
||||
bme680_bsec_id: bme680_sensor
|
||||
temperature:
|
||||
name: "BME680 Temperature"
|
||||
id: bme680_temperature
|
||||
pressure:
|
||||
name: "BME680 Pressure"
|
||||
id: bme680_pressure
|
||||
humidity:
|
||||
name: "BME680 Relative Humidity"
|
||||
id: bme680_humidity
|
||||
iaq:
|
||||
name: "BME680 IAQ"
|
||||
id: bme680_iaq
|
||||
co2_equivalent:
|
||||
name: "BME680 CO2 Equivalent"
|
||||
breath_voc_equivalent:
|
||||
name: "BME680 Breath VOC Equivalent"
|
||||
gas_resistance:
|
||||
name: "BME680 Gas Resistance"
|
||||
id: bme680_gas_resistance
|
||||
internal: yes
|
||||
|
||||
- platform: absolute_humidity
|
||||
name: "BME680 Absolute Humidity"
|
||||
temperature: bme680_temperature
|
||||
humidity: bme680_humidity
|
||||
|
||||
- platform: tsl2591
|
||||
address: 0x29
|
||||
update_interval: 1s
|
||||
integration_time: 200ms
|
||||
power_save_mode: no
|
||||
gain: auto
|
||||
device_factor: 53
|
||||
glass_attenuation_factor: 7.7
|
||||
visible:
|
||||
name: "TSL2591 Raw Visible"
|
||||
infrared:
|
||||
name: "TSL2591 Raw Infrared"
|
||||
full_spectrum:
|
||||
name: "TSL2591 Raw Full Spectrum"
|
||||
calculated_lux:
|
||||
id: tsl2591_lux
|
||||
name: "TSL2591 Illumination"
|
||||
unit_of_measurement: Lux
|
||||
on_value:
|
||||
- script.execute: light_handler
|
||||
actual_gain:
|
||||
id: "actual_gain"
|
||||
name: "TSL2591 Gain"
|
||||
|
||||
- platform: ld2410
|
||||
ld2410_id: ld2410_radar
|
||||
moving_distance:
|
||||
name: "LD2410C Moving Distance"
|
||||
id: moving_distance
|
||||
icon: mdi:signal-distance-variant
|
||||
still_distance:
|
||||
name: "LD2410C Still Distance"
|
||||
id: still_distance
|
||||
icon: mdi:signal-distance-variant
|
||||
moving_energy:
|
||||
name: "LD2410C Move Energy"
|
||||
icon: mdi:flash
|
||||
still_energy:
|
||||
name: "LD2410C Still Energy"
|
||||
icon: mdi:flash
|
||||
detection_distance:
|
||||
name: "LD2410C Presence Distance"
|
||||
icon: mdi:signal-distance-variant
|
||||
|
||||
- platform: uptime
|
||||
name: "ESP32 Uptime"
|
||||
icon: mdi:clock-alert
|
||||
update_interval: 5s
|
||||
entity_category: diagnostic
|
||||
|
||||
- platform: wifi_signal
|
||||
name: "WiFi RSSI"
|
||||
icon: mdi:wifi-strength-2
|
||||
update_interval: 5s
|
||||
entity_category: diagnostic
|
||||
|
||||
- platform: internal_temperature
|
||||
name: "ESP32 Temperature"
|
||||
icon: mdi:thermometer
|
||||
unit_of_measurement: °C
|
||||
device_class: TEMPERATURE
|
||||
update_interval: 5s
|
||||
entity_category: diagnostic
|
||||
|
||||
- platform: template
|
||||
name: "ESP32 CPU Frequency"
|
||||
icon: mdi:cpu-32-bit
|
||||
accuracy_decimals: 1
|
||||
unit_of_measurement: MHz
|
||||
update_interval: 5s
|
||||
lambda: |-
|
||||
return ets_get_cpu_frequency();
|
||||
entity_category: diagnostic
|
||||
|
||||
- platform: template
|
||||
name: "ESP32 Free Memory"
|
||||
icon: mdi:memory
|
||||
unit_of_measurement: 'kB'
|
||||
state_class: measurement
|
||||
update_interval: 5s
|
||||
lambda: |-
|
||||
return heap_caps_get_free_size(MALLOC_CAP_INTERNAL) / 1024;
|
||||
entity_category: diagnostic
|
||||
|
||||
text_sensor:
|
||||
- platform: bme680_bsec
|
||||
bme680_bsec_id: bme680_sensor
|
||||
iaq_accuracy:
|
||||
name: "BME680 IAQ Accuracy"
|
||||
|
||||
- platform: template
|
||||
name: "BME680 IAQ Classification"
|
||||
icon: "mdi:air-filter"
|
||||
update_interval: 15s
|
||||
lambda: |-
|
||||
int iaq = int(id(bme680_iaq).state);
|
||||
if (iaq <= 50) {
|
||||
return {"Excellent (" + to_string(iaq) + ")"};
|
||||
}
|
||||
else if (iaq <= 100) {
|
||||
return {"Good (" + to_string(iaq) + ")"};
|
||||
}
|
||||
else if (iaq <= 150) {
|
||||
return {"Fair (" + to_string(iaq) + ")"};
|
||||
}
|
||||
else if (iaq <= 200) {
|
||||
return {"Moderate (" + to_string(iaq) + ")"};
|
||||
}
|
||||
else if (iaq <= 250) {
|
||||
return {"Bad (" + to_string(iaq) + ")"};
|
||||
}
|
||||
else if (iaq <= 350) {
|
||||
return {"Very Bad (" + to_string(iaq) + ")"};
|
||||
}
|
||||
else if (iaq <= 500) {
|
||||
return {"Terrible (" + to_string(iaq) + ")"};
|
||||
}
|
||||
else {
|
||||
return {"Unknown (" + to_string(iaq) + ")"};
|
||||
}
|
||||
|
||||
- platform: wifi_info
|
||||
ip_address:
|
||||
name: "WiFi IP Address"
|
||||
ssid:
|
||||
name: "WiFi SSID"
|
||||
bssid:
|
||||
name: "WiFi BSSID"
|
||||
mac_address:
|
||||
name: "WiFi MAC Address"
|
||||
|
||||
- platform: ld2410
|
||||
version:
|
||||
name: "LD2410C Firmware Version"
|
||||
mac_address:
|
||||
name: "LD2410C MAC Address"
|
||||
|
||||
button:
|
||||
- platform: ld2410
|
||||
restart:
|
||||
name: "LD2410C Restart"
|
||||
icon: mdi:power-cycle
|
||||
entity_category: diagnostic
|
||||
factory_reset:
|
||||
name: "LD2410C Factory Reset"
|
||||
entity_category: diagnostic
|
||||
|
||||
- platform: restart
|
||||
name: "ESP32 Restart"
|
||||
icon: mdi:power-cycle
|
||||
entity_category: diagnostic
|
||||
|
||||
switch:
|
||||
- platform: template
|
||||
name: "Enable Wake Word"
|
||||
icon: mdi:account-voice
|
||||
id: use_wake_word
|
||||
optimistic: true
|
||||
restore_mode: ALWAYS_OFF
|
||||
entity_category: config
|
||||
on_turn_on:
|
||||
- lambda: id(assist).set_use_wake_word(true);
|
||||
- if:
|
||||
condition:
|
||||
not:
|
||||
- voice_assistant.is_running
|
||||
then:
|
||||
- voice_assistant.start_continuous
|
||||
on_turn_off:
|
||||
- voice_assistant.stop
|
||||
- lambda: id(assist).set_use_wake_word(false);
|
||||
|
||||
- platform: ld2410
|
||||
engineering_mode:
|
||||
name: "LD2410C Engineering Mode"
|
||||
entity_category: diagnostic
|
||||
bluetooth:
|
||||
name: "LD2410C Bluetooth"
|
||||
entity_category: diagnostic
|
||||
|
||||
number:
|
||||
# PIR Hold Time:
|
||||
# The number of seconds after motion detection for the PIR sensor to remain held on
|
||||
- platform: template
|
||||
name: "PIR Hold Time"
|
||||
id: pir_hold_time_setter
|
||||
min_value: 0
|
||||
max_value: 60
|
||||
step: 5
|
||||
lambda: |-
|
||||
return id(pir_hold_time);
|
||||
set_action:
|
||||
then:
|
||||
- globals.set:
|
||||
id: pir_hold_time
|
||||
value: !lambda 'return int(x);'
|
||||
|
||||
# Light Presence Threshold
|
||||
# The minimum Lux value to consider presence based on the ambient light level
|
||||
- platform: template
|
||||
name: "Light Presence Threshold"
|
||||
id: light_presence_threshold_setter
|
||||
min_value: 0
|
||||
max_value: 200
|
||||
step: 5
|
||||
lambda: |-
|
||||
return id(light_presence_threshold);
|
||||
set_action:
|
||||
then:
|
||||
- globals.set:
|
||||
id: light_presence_threshold
|
||||
value: !lambda 'return int(x);'
|
||||
|
||||
- platform: ld2410
|
||||
timeout:
|
||||
name: "LD2410C Timeout"
|
||||
light_threshold:
|
||||
name: "LD2410C Light Threshold"
|
||||
max_move_distance_gate:
|
||||
name: "LD2410C Max Move Distance Gate"
|
||||
max_still_distance_gate:
|
||||
name: "LD2410C Max Still Distance Gate"
|
||||
g0:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate0 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate0 Still Threshold"
|
||||
g1:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate1 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate1 Still Threshold"
|
||||
g2:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate2 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate2 Still Threshold"
|
||||
g3:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate3 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate3 Still Threshold"
|
||||
g4:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate4 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate4 Still Threshold"
|
||||
g5:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate5 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate5 Still Threshold"
|
||||
g6:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate6 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate6 Still Threshold"
|
||||
g7:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate7 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate7 Still Threshold"
|
||||
g8:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate8 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate8 Still Threshold"
|
||||
|
||||
select:
|
||||
|
||||
# Occupancy Detect Mode:
|
||||
# This selector defines the detection mode for the integrated occupancy sensor. Depending on the
|
||||
# selected option, only the given sensor(s) will be used to judge when occupancy begins (i.e.
|
||||
# when the given sensor(s) detect, occupancy detects).
|
||||
# * PIR + Radar + Light:
|
||||
# All 3 sensors reporting detection simultaneously will begin occupancy
|
||||
# * PIR + Radar
|
||||
# Both PIR and Radar sensors reporting detection simultaneously will begin occupancy
|
||||
# * PIR + Light
|
||||
# Both PIR and Light sensors reporting detection simultaneously will begin occupancy
|
||||
# * Radar + Light
|
||||
# Both Radar and Light sensors reporting detection simultaneously will begin occupancy
|
||||
# * PIR Only
|
||||
# PIR sensor reporting detection will begin occupancy
|
||||
# * Radar Only
|
||||
# Radar sensor reporting detection will begin occupancy
|
||||
# * Light Only
|
||||
# Light sensor reporting detection will begin occupancy
|
||||
# * None
|
||||
# No sensors will begin occupancy and the integrated occupancy functionality is disabled
|
||||
# Values are reported as integers using bitwise logic:
|
||||
# Bit 2: PIR
|
||||
# Bit 1: Radar
|
||||
# Bit 0: Light
|
||||
- platform: template
|
||||
name: "Occupancy Detect Mode"
|
||||
id: occupancy_detect_mode_setter
|
||||
options:
|
||||
- "PIR + Radar + Light" # 111 = 7
|
||||
- "PIR + Radar" # 110 = 6
|
||||
- "PIR + Light" # 101 = 5
|
||||
- "Radar + Light" # 011 = 3
|
||||
- "PIR Only" # 100 = 4
|
||||
- "Radar Only" # 010 = 2
|
||||
- "Light Only" # 001 = 1
|
||||
- "None" # 000 = 0
|
||||
initial_option: "None"
|
||||
optimistic: yes
|
||||
restore_value: yes
|
||||
set_action:
|
||||
- globals.set:
|
||||
id: occupancy_detect_mode
|
||||
value: !lambda |-
|
||||
ESP_LOGD("occupancy_detect_mode_setter", x.c_str());
|
||||
if (x == "PIR + Radar + Light") {
|
||||
return 7;
|
||||
} else if (x == "PIR + Radar") {
|
||||
return 6;
|
||||
} else if (x == "PIR + Light") {
|
||||
return 5;
|
||||
} else if (x == "Radar + Light") {
|
||||
return 3;
|
||||
} else if (x == "PIR Only") {
|
||||
return 4;
|
||||
} else if (x == "Radar Only") {
|
||||
return 2;
|
||||
} else if (x == "Light Only") {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Occupancy Clear Mode:
|
||||
# This selector defines the clear mode for the integrated occupancy sensor. Depending on the
|
||||
# selected option, only the given sensor(s) will be used to judge when occupancy ends (i.e.
|
||||
# when the given sensor(s) clear, occupancy clears).
|
||||
# * PIR + Radar + Light:
|
||||
# Any of the 3 sensors clearing will end occupancy
|
||||
# * PIR + Radar:
|
||||
# Either of the PIR or Radar sensors clearing will end occupancy
|
||||
# * PIR + Light:
|
||||
# Either of the PIR or Light sensors clearing will end occupancy
|
||||
# * Radar + Light:
|
||||
# Either of the Radar or Light sensors clearing will end occupancy
|
||||
# * PIR Only
|
||||
# PIR sensor clearing will end occupancy
|
||||
# * Radar Only
|
||||
# Radar sensor clearing will end occupancy
|
||||
# * Light Only
|
||||
# Light sensor clearing will end occupancy
|
||||
# * None
|
||||
# No sensors will end occupancy; state will persist indefinitely once triggered
|
||||
# Values are reported as integers using bitwise logic:
|
||||
# Bit 0: PIR
|
||||
# Bit 1: Radar
|
||||
# Bit 2: Light
|
||||
- platform: template
|
||||
name: "Occupancy Clear Mode"
|
||||
id: occupancy_clear_mode_setter
|
||||
options:
|
||||
- "PIR + Radar + Light" # 111 = 7
|
||||
- "PIR + Radar" # 110 = 6
|
||||
- "PIR + Light" # 101 = 5
|
||||
- "Radar + Light" # 011 = 3
|
||||
- "PIR Only" # 100 = 4
|
||||
- "Radar Only" # 010 = 2
|
||||
- "Light Only" # 001 = 1
|
||||
- "None" # 000 = 0
|
||||
initial_option: "None"
|
||||
optimistic: yes
|
||||
restore_value: yes
|
||||
set_action:
|
||||
- globals.set:
|
||||
id: occupancy_clear_mode
|
||||
value: !lambda |-
|
||||
ESP_LOGD("occupancy_detect_mode_setter", x.c_str());
|
||||
if (x == "PIR + Radar + Light") {
|
||||
return 7;
|
||||
} else if (x == "PIR + Radar") {
|
||||
return 6;
|
||||
} else if (x == "PIR + Light") {
|
||||
return 5;
|
||||
} else if (x == "Radar + Light") {
|
||||
return 3;
|
||||
} else if (x == "PIR Only") {
|
||||
return 4;
|
||||
} else if (x == "Radar Only") {
|
||||
return 2;
|
||||
} else if (x == "Light Only") {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
- platform: ld2410
|
||||
distance_resolution:
|
||||
name: "LD2410C Distance Resolution"
|
@@ -1,861 +0,0 @@
|
||||
---
|
||||
|
||||
###############################################################################
|
||||
# SuperSensor v1.0 ESPHome configuration
|
||||
###############################################################################
|
||||
#
|
||||
# Copyright (C) 2023 Joshua M. Boniface <joshua@boniface.me>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
esphome:
|
||||
name: supersensor
|
||||
name_add_mac_suffix: true
|
||||
friendly_name: "Supersensor"
|
||||
project:
|
||||
name: joshuaboniface.supersensor
|
||||
version: "0.1"
|
||||
on_boot:
|
||||
- priority: 600
|
||||
then:
|
||||
- lambda: |-
|
||||
id(supersensor_occupancy).publish_state(false);
|
||||
id(pir_presence).publish_state(false);
|
||||
id(light_presence).publish_state(false);
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
effect: flash_white
|
||||
|
||||
dashboard_import:
|
||||
package_import_url: github://joshuaboniface/supersensor/supersensor.yaml
|
||||
import_full_config: false
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
framework:
|
||||
type: esp-idf
|
||||
sdkconfig_options:
|
||||
CONFIG_ESP32_DEFAULT_CPU_FREQ_240: "y"
|
||||
CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ: "240"
|
||||
CONFIG_ESP32_DATA_CACHE_64KB: "y"
|
||||
CONFIG_ESP32_DATA_CACHE_LINE_64B: "y"
|
||||
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: "y"
|
||||
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ: "240"
|
||||
CONFIG_ESP32S3_DATA_CACHE_64KB: "y"
|
||||
CONFIG_ESP32S3_DATA_CACHE_LINE_64B: "y"
|
||||
|
||||
globals:
|
||||
- id: pir_hold_time
|
||||
type: int
|
||||
restore_value: yes
|
||||
initial_value: "15"
|
||||
|
||||
- id: light_presence_threshold
|
||||
type: int
|
||||
restore_value: yes
|
||||
initial_value: "30"
|
||||
|
||||
- id: occupancy_detect_mode
|
||||
type: int
|
||||
restore_value: yes
|
||||
initial_value: "0"
|
||||
|
||||
- id: occupancy_clear_mode
|
||||
type: int
|
||||
restore_value: yes
|
||||
initial_value: "0"
|
||||
|
||||
script:
|
||||
- id: pir_handler
|
||||
then:
|
||||
- lambda: |-
|
||||
id(pir_presence).publish_state(true);
|
||||
- while:
|
||||
condition:
|
||||
binary_sensor.is_on: pir_gpio
|
||||
then:
|
||||
- delay: !lambda 'return(id(pir_hold_time) * 1000);'
|
||||
- lambda: |-
|
||||
id(pir_presence).publish_state(false);
|
||||
|
||||
- id: light_handler
|
||||
then:
|
||||
- lambda: |-
|
||||
if (id(tsl2591_lux).state >= id(light_presence_threshold)) {
|
||||
id(light_presence).publish_state(true);
|
||||
} else {
|
||||
id(light_presence).publish_state(false);
|
||||
}
|
||||
|
||||
- id: occupancy_detect_handler
|
||||
then:
|
||||
- lambda: |-
|
||||
ESP_LOGD("occupancy_detect_handler", "Occupancy detect handler triggered");
|
||||
|
||||
// Get the current values of our presence sensors
|
||||
bool pir = id(pir_presence).state;
|
||||
bool radar = id(radar_presence).state;
|
||||
bool light = id(light_presence).state;
|
||||
|
||||
// Determine if PIR counts (2nd bit of presence_type)
|
||||
int pir_counts = (id(occupancy_detect_mode) & ( 1 << 2 )) >> 2;
|
||||
|
||||
// Determine if Radar counts (1st bit of presence_type)
|
||||
int radar_counts = (id(occupancy_detect_mode) & ( 1 << 1 )) >> 1;
|
||||
|
||||
// Determine if Light counts (0th bit of presence_type)
|
||||
int light_counts = (id(occupancy_detect_mode) & ( 1 << 0 )) >> 0;
|
||||
|
||||
// Determine our results
|
||||
if (pir_counts & radar_counts & light_counts) {
|
||||
// Logical AND of pir & radar & light
|
||||
ESP_LOGD("occupancy_detect_handler", "PIR & Radar & Light: %i", pir & radar & light);
|
||||
id(supersensor_occupancy).publish_state(pir & radar & light);
|
||||
} else if (pir_counts & radar_counts) {
|
||||
// Logical AND of pir & radar
|
||||
ESP_LOGD("occupancy_detect_handler", "PIR & Radar: %i", pir & radar);
|
||||
id(supersensor_occupancy).publish_state(pir & radar);
|
||||
} else if (pir_counts & light_counts) {
|
||||
// Logical AND of pir & light
|
||||
ESP_LOGD("occupancy_detect_handler", "PIR & Light: %i", pir & light);
|
||||
id(supersensor_occupancy).publish_state(pir & light);
|
||||
} else if (radar_counts & light_counts) {
|
||||
// Logical AND of radar & light
|
||||
ESP_LOGD("occupancy_detect_handler", "Radar & Light: %i", radar & light);
|
||||
id(supersensor_occupancy).publish_state(radar & light);
|
||||
} else if (pir_counts) {
|
||||
// Only pir
|
||||
ESP_LOGD("occupancy_detect_handler", "PIR: %i", pir);
|
||||
id(supersensor_occupancy).publish_state(pir);
|
||||
} else if (radar_counts) {
|
||||
// Only radar
|
||||
ESP_LOGD("occupancy_detect_handler", "Radar: %i", radar);
|
||||
id(supersensor_occupancy).publish_state(radar);
|
||||
} else if (light_counts) {
|
||||
// Only light
|
||||
ESP_LOGD("occupancy_detect_handler", "Light: %i", light);
|
||||
id(supersensor_occupancy).publish_state(light);
|
||||
} else {
|
||||
ESP_LOGD("occupancy_detect_handler", "None");
|
||||
id(supersensor_occupancy).publish_state(false);
|
||||
}
|
||||
|
||||
- id: occupancy_clear_handler
|
||||
then:
|
||||
- lambda: |-
|
||||
ESP_LOGD("occupancy_clear_handler", "Occupancy clear handler triggered");
|
||||
|
||||
// Get the current values of our presence sensors
|
||||
bool pir = id(pir_presence).state;
|
||||
bool radar = id(radar_presence).state;
|
||||
bool light = id(light_presence).state;
|
||||
|
||||
// Determine if PIR counts (2nd bit of presence_type)
|
||||
int pir_counts = (id(occupancy_clear_mode) & ( 1 << 2 )) >> 2;
|
||||
|
||||
// Determine if Radar counts (1st bit of presence_type)
|
||||
int radar_counts = (id(occupancy_clear_mode) & ( 1 << 1 )) >> 1;
|
||||
|
||||
// Determine if Light counts (0th bit of presence_type)
|
||||
int light_counts = (id(occupancy_clear_mode) & ( 1 << 0 )) >> 0;
|
||||
|
||||
// Determine our results
|
||||
if (pir_counts & radar_counts & light_counts) {
|
||||
// Logical AND of pir & radar & light
|
||||
ESP_LOGD("occupancy_clear_handler", "PIR & Radar & Light: %i", pir & radar & light);
|
||||
id(supersensor_occupancy).publish_state(pir & radar & light);
|
||||
} else if (pir_counts & radar_counts) {
|
||||
// Logical AND of pir & radar
|
||||
ESP_LOGD("occupancy_clear_handler", "PIR & Radar: %i", pir & radar);
|
||||
id(supersensor_occupancy).publish_state(pir & radar);
|
||||
} else if (pir_counts & light_counts) {
|
||||
// Logical AND of pir & light
|
||||
ESP_LOGD("occupancy_clear_handler", "PIR & Light: %i", pir & light);
|
||||
id(supersensor_occupancy).publish_state(pir & light);
|
||||
} else if (radar_counts & light_counts) {
|
||||
// Logical AND of radar & light
|
||||
ESP_LOGD("occupancy_clear_handler", "Radar & Light: %i", radar & light);
|
||||
id(supersensor_occupancy).publish_state(radar & light);
|
||||
} else if (pir_counts) {
|
||||
// Only pir
|
||||
ESP_LOGD("occupancy_clear_handler", "PIR: %i", pir);
|
||||
id(supersensor_occupancy).publish_state(pir);
|
||||
} else if (radar_counts) {
|
||||
// Only radar
|
||||
ESP_LOGD("occupancy_clear_handler", "Radar: %i", radar);
|
||||
id(supersensor_occupancy).publish_state(radar);
|
||||
} else if (light_counts) {
|
||||
// Only light
|
||||
ESP_LOGD("occupancy_clear_handler", "Light: %i", light);
|
||||
id(supersensor_occupancy).publish_state(light);
|
||||
} else {
|
||||
ESP_LOGD("occupancy_clear_handler", "None");
|
||||
id(supersensor_occupancy).publish_state(false);
|
||||
}
|
||||
|
||||
logger:
|
||||
level: DEBUG
|
||||
baud_rate: 115200
|
||||
|
||||
api:
|
||||
encryption:
|
||||
key: !secret api_encryption_key
|
||||
on_client_disconnected:
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
effect: flash_white
|
||||
- switch.turn_off: use_wake_word
|
||||
on_client_connected:
|
||||
# This absolute absurdity is required to prevent
|
||||
# "no wake word detected" failure loops.
|
||||
- switch.turn_on: use_wake_word
|
||||
- delay: 2s
|
||||
- switch.turn_off: use_wake_word
|
||||
- delay: 2s
|
||||
- switch.turn_on: use_wake_word
|
||||
- delay: 2s
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
|
||||
ota:
|
||||
password: !secret ota_password
|
||||
safe_mode: false
|
||||
|
||||
web_server:
|
||||
port: 80
|
||||
auth:
|
||||
username: !secret web_auth_username
|
||||
password: !secret web_auth_password
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
domain: !secret wifi_domain
|
||||
power_save_mode: LIGHT
|
||||
reboot_timeout: 5min
|
||||
|
||||
uart:
|
||||
id: ld2410_uart
|
||||
rx_pin: GPIO19
|
||||
tx_pin: GPIO18
|
||||
baud_rate: 256000
|
||||
data_bits: 8
|
||||
stop_bits: 1
|
||||
parity: NONE
|
||||
|
||||
i2c:
|
||||
sda: GPIO16
|
||||
scl: GPIO17
|
||||
scan: true
|
||||
|
||||
i2s_audio:
|
||||
i2s_lrclk_pin: GPIO26
|
||||
i2s_bclk_pin: GPIO27
|
||||
|
||||
microphone:
|
||||
- platform: i2s_audio
|
||||
id: mic
|
||||
adc_type: external
|
||||
i2s_din_pin: GPIO14
|
||||
pdm: false
|
||||
|
||||
voice_assistant:
|
||||
microphone: mic
|
||||
use_wake_word: false
|
||||
noise_suppression_level: 2
|
||||
auto_gain: 31dBFS
|
||||
volume_multiplier: 4.0
|
||||
id: assist
|
||||
on_error:
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
transition_length: 1s
|
||||
- logger.log: "Voice Assistant encountered an error; restarting it"
|
||||
- switch.turn_off: use_wake_word
|
||||
- delay: 1s
|
||||
- switch.turn_on: use_wake_word
|
||||
on_wake_word_detected:
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
red: 0
|
||||
green: 0
|
||||
blue: 1
|
||||
on_listening:
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
red: 0
|
||||
green: 0
|
||||
blue: 1
|
||||
on_stt_end:
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
transition_length: 1s
|
||||
on_tts_start:
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
transition_length: 1s
|
||||
- if:
|
||||
condition:
|
||||
lambda: return x != "Sorry, I couldn't understand that";
|
||||
then:
|
||||
- logger.log: "Command successful!"
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
effect: hold
|
||||
red: 0
|
||||
green: 1
|
||||
blue: 0
|
||||
else:
|
||||
- logger.log: "Command failed!"
|
||||
- light.turn_on:
|
||||
id: output_led
|
||||
effect: hold
|
||||
red: 1
|
||||
green: 0
|
||||
blue: 0
|
||||
|
||||
light:
|
||||
- platform: rgb
|
||||
id: output_led
|
||||
red: rgb_r
|
||||
green: rgb_g
|
||||
blue: rgb_b
|
||||
default_transition_length: 0.15s
|
||||
flash_transition_length: 0.15s
|
||||
effects:
|
||||
- strobe:
|
||||
name: flash_white
|
||||
colors:
|
||||
- state: true
|
||||
brightness: 50%
|
||||
red: 100%
|
||||
green: 100%
|
||||
blue: 100%
|
||||
duration: 0.5s
|
||||
- state: false
|
||||
duration: 0.5s
|
||||
- automation:
|
||||
name: hold
|
||||
sequence:
|
||||
- delay: 5s
|
||||
- light.turn_off:
|
||||
id: output_led
|
||||
transition_length: 1s
|
||||
|
||||
output:
|
||||
- platform: ledc
|
||||
id: rgb_r
|
||||
pin: GPIO32
|
||||
- platform: ledc
|
||||
id: rgb_g
|
||||
pin: GPIO33
|
||||
- platform: ledc
|
||||
id: rgb_b
|
||||
pin: GPIO25
|
||||
|
||||
ld2410:
|
||||
id: ld2410_radar
|
||||
uart_id: ld2410_uart
|
||||
# These default values are captured here for
|
||||
# posterity. They are configured below.
|
||||
# max_move_distance : 6m
|
||||
# max_still_distance: 0.75m
|
||||
# g0_move_threshold: 10
|
||||
# g0_still_threshold: 20
|
||||
# g1_move_threshold: 10
|
||||
# g1_still_threshold: 20
|
||||
# g2_move_threshold: 20
|
||||
# g2_still_threshold: 21
|
||||
# g3_move_threshold: 30
|
||||
# g3_still_threshold: 31
|
||||
# g4_move_threshold: 40
|
||||
# g4_still_threshold: 41
|
||||
# g5_move_threshold: 50
|
||||
# g5_still_threshold: 51
|
||||
# g6_move_threshold: 60
|
||||
# g6_still_threshold: 61
|
||||
# g7_move_threshold: 70
|
||||
# g7_still_threshold: 71
|
||||
# g8_move_threshold: 80
|
||||
# g8_still_threshold: 81
|
||||
|
||||
binary_sensor:
|
||||
- platform: template
|
||||
name: "SuperSensor Occupancy"
|
||||
id: supersensor_occupancy
|
||||
device_class: occupancy
|
||||
|
||||
- platform: gpio
|
||||
name: "PIR GPIO"
|
||||
id: pir_gpio
|
||||
pin: GPIO13
|
||||
internal: false
|
||||
device_class: motion
|
||||
on_press:
|
||||
- script.stop: pir_handler
|
||||
- script.execute: pir_handler
|
||||
|
||||
- platform: template
|
||||
name: "PIR Presence"
|
||||
id: pir_presence
|
||||
device_class: motion
|
||||
on_press:
|
||||
- script.execute: occupancy_detect_handler
|
||||
on_release:
|
||||
- script.execute: occupancy_clear_handler
|
||||
|
||||
- platform: template
|
||||
name: "Light Presence"
|
||||
id: light_presence
|
||||
device_class: motion
|
||||
on_press:
|
||||
- script.execute: occupancy_detect_handler
|
||||
on_release:
|
||||
- script.execute: occupancy_clear_handler
|
||||
|
||||
- platform: ld2410
|
||||
ld2410_id: ld2410_radar
|
||||
has_target:
|
||||
name: "LD2410C Presence"
|
||||
id: radar_presence
|
||||
device_class: motion
|
||||
on_press:
|
||||
- script.execute: occupancy_detect_handler
|
||||
on_release:
|
||||
- script.execute: occupancy_clear_handler
|
||||
has_moving_target:
|
||||
name: "LD2410C Moving Target"
|
||||
has_still_target:
|
||||
name: "LD2410C Still Target"
|
||||
|
||||
sensor:
|
||||
- platform: bme680
|
||||
temperature:
|
||||
name: "BME680 Temperature"
|
||||
id: bme680_temperature
|
||||
pressure:
|
||||
name: "BME680 Pressure"
|
||||
id: bme680_pressure
|
||||
humidity:
|
||||
name: "BME680 Relative Humidity"
|
||||
id: bme680_humidity
|
||||
gas_resistance:
|
||||
name: "BME680 Gas Resistance"
|
||||
id: bme680_gas_resistance
|
||||
address: 0x77
|
||||
update_interval: 5s
|
||||
|
||||
- platform: absolute_humidity
|
||||
name: "BME680 Absolute Humidity"
|
||||
temperature: bme680_temperature
|
||||
humidity: bme680_humidity
|
||||
|
||||
- platform: template
|
||||
name: "BME680 Indoor Air Quality"
|
||||
id: bme680_iaq
|
||||
icon: "mdi:gauge"
|
||||
# caulculation: comp_gas = log(R_gas[ohm]) + 0.04 log(Ohm)/%rh * hum[%rh]
|
||||
lambda: |-
|
||||
return float(log(id(bme680_gas_resistance).state) + 0.04 * id(bme680_humidity).state);
|
||||
|
||||
- platform: tsl2591
|
||||
address: 0x29
|
||||
update_interval: 1s
|
||||
integration_time: 200ms
|
||||
power_save_mode: no
|
||||
gain: auto
|
||||
device_factor: 53
|
||||
glass_attenuation_factor: 7.7
|
||||
visible:
|
||||
name: "TSL2591 Raw Visible"
|
||||
infrared:
|
||||
name: "TSL2591 Raw Infrared"
|
||||
full_spectrum:
|
||||
name: "TSL2591 Raw Full Spectrum"
|
||||
calculated_lux:
|
||||
id: tsl2591_lux
|
||||
name: "TSL2591 Illumination"
|
||||
unit_of_measurement: Lux
|
||||
on_value:
|
||||
- script.execute: light_handler
|
||||
actual_gain:
|
||||
id: "actual_gain"
|
||||
name: "TSL2591 Gain"
|
||||
|
||||
- platform: ld2410
|
||||
ld2410_id: ld2410_radar
|
||||
moving_distance:
|
||||
name: "LD2410C Moving Distance"
|
||||
id: moving_distance
|
||||
still_distance:
|
||||
name: "LD2410C Still Distance"
|
||||
id: still_distance
|
||||
moving_energy:
|
||||
name: "LD2410C Move Energy"
|
||||
still_energy:
|
||||
name: "LD2410C Still Energy"
|
||||
detection_distance:
|
||||
name: "LD2410C Presence Distance"
|
||||
|
||||
- platform: uptime
|
||||
name: "ESP32 Uptime"
|
||||
icon: mdi:clock-alert
|
||||
update_interval: 5s
|
||||
entity_category: diagnostic
|
||||
|
||||
- platform: wifi_signal
|
||||
name: "WiFi RSSI"
|
||||
icon: mdi:wifi-strength-2
|
||||
update_interval: 5s
|
||||
entity_category: diagnostic
|
||||
|
||||
- platform: internal_temperature
|
||||
name: "ESP32 Temperature"
|
||||
icon: mdi:thermometer
|
||||
unit_of_measurement: °C
|
||||
device_class: TEMPERATURE
|
||||
update_interval: 5s
|
||||
entity_category: diagnostic
|
||||
|
||||
- platform: template
|
||||
name: "ESP32 CPU Frequency"
|
||||
icon: mdi:cpu-32-bit
|
||||
accuracy_decimals: 1
|
||||
unit_of_measurement: MHz
|
||||
update_interval: 5s
|
||||
lambda: |-
|
||||
return ets_get_cpu_frequency();
|
||||
entity_category: diagnostic
|
||||
|
||||
- platform: template
|
||||
name: "ESP32 Free Memory"
|
||||
icon: mdi:memory
|
||||
unit_of_measurement: 'kB'
|
||||
state_class: measurement
|
||||
update_interval: 5s
|
||||
lambda: |-
|
||||
return heap_caps_get_free_size(MALLOC_CAP_INTERNAL) / 1024;
|
||||
entity_category: diagnostic
|
||||
|
||||
text_sensor:
|
||||
- platform: template
|
||||
name: "BME680 IAQ Classification"
|
||||
icon: "mdi:air-filter"
|
||||
update_interval: 15s
|
||||
lambda: |-
|
||||
int iaq = int(id(bme680_iaq).state);
|
||||
if (iaq <= 50) {
|
||||
return {"Excellent (" + to_string(iaq) + ")"};
|
||||
}
|
||||
else if (iaq <= 100) {
|
||||
return {"Good (" + to_string(iaq) + ")"};
|
||||
}
|
||||
else if (iaq <= 150) {
|
||||
return {"Fair (" + to_string(iaq) + ")"};
|
||||
}
|
||||
else if (iaq <= 200) {
|
||||
return {"Moderate (" + to_string(iaq) + ")"};
|
||||
}
|
||||
else if (iaq <= 250) {
|
||||
return {"Bad (" + to_string(iaq) + ")"};
|
||||
}
|
||||
else if (iaq <= 350) {
|
||||
return {"Very Bad (" + to_string(iaq) + ")"};
|
||||
}
|
||||
else if (iaq <= 500) {
|
||||
return {"Terrible (" + to_string(iaq) + ")"};
|
||||
}
|
||||
else {
|
||||
return {"Unknown (" + to_string(iaq) + ")"};
|
||||
}
|
||||
|
||||
- platform: wifi_info
|
||||
ip_address:
|
||||
name: "WiFi IP Address"
|
||||
ssid:
|
||||
name: "WiFi SSID"
|
||||
bssid:
|
||||
name: "WiFi BSSID"
|
||||
mac_address:
|
||||
name: "WiFi MAC Address"
|
||||
|
||||
- platform: ld2410
|
||||
version:
|
||||
name: "LD2410C Firmware Version"
|
||||
mac_address:
|
||||
name: "LD2410C MAC Address"
|
||||
|
||||
button:
|
||||
- platform: ld2410
|
||||
restart:
|
||||
name: "LD2410C Restart"
|
||||
icon: mdi:power-cycle
|
||||
entity_category: diagnostic
|
||||
factory_reset:
|
||||
name: "LD2410C Factory Reset"
|
||||
entity_category: diagnostic
|
||||
|
||||
- platform: restart
|
||||
name: "ESP32 Restart"
|
||||
icon: mdi:power-cycle
|
||||
entity_category: diagnostic
|
||||
|
||||
switch:
|
||||
- platform: template
|
||||
name: "Enable Wake Word"
|
||||
icon: mdi:account-voice
|
||||
id: use_wake_word
|
||||
optimistic: true
|
||||
restore_mode: ALWAYS_OFF
|
||||
entity_category: config
|
||||
on_turn_on:
|
||||
- lambda: id(assist).set_use_wake_word(true);
|
||||
- if:
|
||||
condition:
|
||||
not:
|
||||
- voice_assistant.is_running
|
||||
then:
|
||||
- voice_assistant.start_continuous
|
||||
on_turn_off:
|
||||
- voice_assistant.stop
|
||||
- lambda: id(assist).set_use_wake_word(false);
|
||||
|
||||
- platform: ld2410
|
||||
engineering_mode:
|
||||
name: "LD2410C Engineering Mode"
|
||||
entity_category: diagnostic
|
||||
bluetooth:
|
||||
name: "LD2410C Bluetooth"
|
||||
entity_category: diagnostic
|
||||
|
||||
number:
|
||||
# PIR Hold Time:
|
||||
# The number of seconds after motion detection for the PIR sensor to remain held on
|
||||
- platform: template
|
||||
name: "PIR Hold Time"
|
||||
id: pir_hold_time_setter
|
||||
min_value: 0
|
||||
max_value: 60
|
||||
step: 5
|
||||
lambda: |-
|
||||
return id(pir_hold_time);
|
||||
set_action:
|
||||
then:
|
||||
- globals.set:
|
||||
id: pir_hold_time
|
||||
value: !lambda 'return int(x);'
|
||||
|
||||
# Light Presence Threshold
|
||||
# The minimum Lux value to consider presence based on the ambient light level
|
||||
- platform: template
|
||||
name: "Light Presence Threshold"
|
||||
id: light_presence_threshold_setter
|
||||
min_value: 0
|
||||
max_value: 200
|
||||
step: 5
|
||||
lambda: |-
|
||||
return id(light_presence_threshold);
|
||||
set_action:
|
||||
then:
|
||||
- globals.set:
|
||||
id: light_presence_threshold
|
||||
value: !lambda 'return int(x);'
|
||||
|
||||
- platform: ld2410
|
||||
timeout:
|
||||
name: "LD2410C Timeout"
|
||||
light_threshold:
|
||||
name: "LD2410C Light Threshold"
|
||||
max_move_distance_gate:
|
||||
name: "LD2410C Max Move Distance Gate"
|
||||
max_still_distance_gate:
|
||||
name: "LD2410C Max Still Distance Gate"
|
||||
g0:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate0 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate0 Still Threshold"
|
||||
g1:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate1 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate1 Still Threshold"
|
||||
g2:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate2 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate2 Still Threshold"
|
||||
g3:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate3 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate3 Still Threshold"
|
||||
g4:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate4 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate4 Still Threshold"
|
||||
g5:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate5 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate5 Still Threshold"
|
||||
g6:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate6 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate6 Still Threshold"
|
||||
g7:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate7 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate7 Still Threshold"
|
||||
g8:
|
||||
move_threshold:
|
||||
name: "LD2410C Gate8 Move Threshold"
|
||||
still_threshold:
|
||||
name: "LD2410C Gate8 Still Threshold"
|
||||
|
||||
select:
|
||||
|
||||
# Occupancy Detect Mode:
|
||||
# This selector defines the detection mode for the integrated occupancy sensor. Depending on the
|
||||
# selected option, only the given sensor(s) will be used to judge when occupancy begins (i.e.
|
||||
# when the given sensor(s) detect, occupancy detects).
|
||||
# * PIR + Radar + Light:
|
||||
# All 3 sensors reporting detection simultaneously will begin occupancy
|
||||
# * PIR + Radar
|
||||
# Both PIR and Radar sensors reporting detection simultaneously will begin occupancy
|
||||
# * PIR + Light
|
||||
# Both PIR and Light sensors reporting detection simultaneously will begin occupancy
|
||||
# * Radar + Light
|
||||
# Both Radar and Light sensors reporting detection simultaneously will begin occupancy
|
||||
# * PIR Only
|
||||
# PIR sensor reporting detection will begin occupancy
|
||||
# * Radar Only
|
||||
# Radar sensor reporting detection will begin occupancy
|
||||
# * Light Only
|
||||
# Light sensor reporting detection will begin occupancy
|
||||
# * None
|
||||
# No sensors will begin occupancy and the integrated occupancy functionality is disabled
|
||||
# Values are reported as integers using bitwise logic:
|
||||
# Bit 2: PIR
|
||||
# Bit 1: Radar
|
||||
# Bit 0: Light
|
||||
- platform: template
|
||||
name: "Occupancy Detect Mode"
|
||||
id: occupancy_detect_mode_setter
|
||||
options:
|
||||
- "PIR + Radar + Light" # 111 = 7
|
||||
- "PIR + Radar" # 110 = 6
|
||||
- "PIR + Light" # 101 = 5
|
||||
- "Radar + Light" # 011 = 3
|
||||
- "PIR Only" # 100 = 4
|
||||
- "Radar Only" # 010 = 2
|
||||
- "Light Only" # 001 = 1
|
||||
- "None" # 000 = 0
|
||||
initial_option: "None"
|
||||
optimistic: yes
|
||||
restore_value: yes
|
||||
set_action:
|
||||
- globals.set:
|
||||
id: occupancy_detect_mode
|
||||
value: !lambda |-
|
||||
ESP_LOGD("occupancy_detect_mode_setter", x.c_str());
|
||||
if (x == "PIR + Radar + Light") {
|
||||
return 7;
|
||||
} else if (x == "PIR + Radar") {
|
||||
return 6;
|
||||
} else if (x == "PIR + Light") {
|
||||
return 5;
|
||||
} else if (x == "Radar + Light") {
|
||||
return 3;
|
||||
} else if (x == "PIR Only") {
|
||||
return 4;
|
||||
} else if (x == "Radar Only") {
|
||||
return 2;
|
||||
} else if (x == "Light Only") {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Occupancy Clear Mode:
|
||||
# This selector defines the clear mode for the integrated occupancy sensor. Depending on the
|
||||
# selected option, only the given sensor(s) will be used to judge when occupancy ends (i.e.
|
||||
# when the given sensor(s) clear, occupancy clears).
|
||||
# * PIR + Radar + Light:
|
||||
# Any of the 3 sensors clearing will end occupancy
|
||||
# * PIR + Radar:
|
||||
# Either of the PIR or Radar sensors clearing will end occupancy
|
||||
# * PIR + Light:
|
||||
# Either of the PIR or Light sensors clearing will end occupancy
|
||||
# * Radar + Light:
|
||||
# Either of the Radar or Light sensors clearing will end occupancy
|
||||
# * PIR Only
|
||||
# PIR sensor clearing will end occupancy
|
||||
# * Radar Only
|
||||
# Radar sensor clearing will end occupancy
|
||||
# * Light Only
|
||||
# Light sensor clearing will end occupancy
|
||||
# * None
|
||||
# No sensors will end occupancy; state will persist indefinitely once triggered
|
||||
# Values are reported as integers using bitwise logic:
|
||||
# Bit 0: PIR
|
||||
# Bit 1: Radar
|
||||
# Bit 2: Light
|
||||
- platform: template
|
||||
name: "Occupancy Clear Mode"
|
||||
id: occupancy_clear_mode_setter
|
||||
options:
|
||||
- "PIR + Radar + Light" # 111 = 7
|
||||
- "PIR + Radar" # 110 = 6
|
||||
- "PIR + Light" # 101 = 5
|
||||
- "Radar + Light" # 011 = 3
|
||||
- "PIR Only" # 100 = 4
|
||||
- "Radar Only" # 010 = 2
|
||||
- "Light Only" # 001 = 1
|
||||
- "None" # 000 = 0
|
||||
initial_option: "None"
|
||||
optimistic: yes
|
||||
restore_value: yes
|
||||
set_action:
|
||||
- globals.set:
|
||||
id: occupancy_clear_mode
|
||||
value: !lambda |-
|
||||
ESP_LOGD("occupancy_detect_mode_setter", x.c_str());
|
||||
if (x == "PIR + Radar + Light") {
|
||||
return 7;
|
||||
} else if (x == "PIR + Radar") {
|
||||
return 6;
|
||||
} else if (x == "PIR + Light") {
|
||||
return 5;
|
||||
} else if (x == "Radar + Light") {
|
||||
return 3;
|
||||
} else if (x == "PIR Only") {
|
||||
return 4;
|
||||
} else if (x == "Radar Only") {
|
||||
return 2;
|
||||
} else if (x == "Light Only") {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
- platform: ld2410
|
||||
distance_resolution:
|
||||
name: "LD2410C Distance Resolution"
|
BIN
case/.images/body-assembly-1.jpg
Normal file
After Width: | Height: | Size: 100 KiB |
BIN
case/.images/body-assembly-2.jpg
Normal file
After Width: | Height: | Size: 89 KiB |
BIN
case/.images/body-assembly-3.jpg
Normal file
After Width: | Height: | Size: 62 KiB |
BIN
case/.images/body-assembly-4.jpg
Normal file
After Width: | Height: | Size: 43 KiB |
BIN
case/.images/body-assembly-5.jpg
Normal file
After Width: | Height: | Size: 118 KiB |
BIN
case/.images/body-assembly-6.jpg
Normal file
After Width: | Height: | Size: 79 KiB |
BIN
case/.images/completed-case.jpg
Normal file
After Width: | Height: | Size: 81 KiB |
BIN
case/.images/completed-face.jpg
Normal file
After Width: | Height: | Size: 72 KiB |
BIN
case/.images/face-assembly-1.jpg
Normal file
After Width: | Height: | Size: 121 KiB |
BIN
case/.images/face-assembly-2.jpg
Normal file
After Width: | Height: | Size: 128 KiB |
BIN
case/.images/face-assembly-3.jpg
Normal file
After Width: | Height: | Size: 151 KiB |
BIN
case/.images/face-assembly-4.jpg
Normal file
After Width: | Height: | Size: 102 KiB |
BIN
case/.images/face-assembly-5.jpg
Normal file
After Width: | Height: | Size: 98 KiB |
BIN
case/.images/face-assembly-6.jpg
Normal file
After Width: | Height: | Size: 105 KiB |
BIN
case/.images/face-assembly-7.jpg
Normal file
After Width: | Height: | Size: 126 KiB |
BIN
case/.images/face-assembly-8.jpg
Normal file
After Width: | Height: | Size: 126 KiB |
BIN
case/.images/final-installation.jpg
Normal file
After Width: | Height: | Size: 92 KiB |
BIN
case/.images/parts.jpg
Normal file
After Width: | Height: | Size: 74 KiB |
427
case/LICENSE
Normal file
@@ -0,0 +1,427 @@
|
||||
Attribution-ShareAlike 4.0 International
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Corporation ("Creative Commons") is not a law firm and
|
||||
does not provide legal services or legal advice. Distribution of
|
||||
Creative Commons public licenses does not create a lawyer-client or
|
||||
other relationship. Creative Commons makes its licenses and related
|
||||
information available on an "as-is" basis. Creative Commons gives no
|
||||
warranties regarding its licenses, any material licensed under their
|
||||
terms and conditions, or any related information. Creative Commons
|
||||
disclaims all liability for damages resulting from their use to the
|
||||
fullest extent possible.
|
||||
|
||||
Using Creative Commons Public Licenses
|
||||
|
||||
Creative Commons public licenses provide a standard set of terms and
|
||||
conditions that creators and other rights holders may use to share
|
||||
original works of authorship and other material subject to copyright
|
||||
and certain other rights specified in the public license below. The
|
||||
following considerations are for informational purposes only, are not
|
||||
exhaustive, and do not form part of our licenses.
|
||||
|
||||
Considerations for licensors: Our public licenses are
|
||||
intended for use by those authorized to give the public
|
||||
permission to use material in ways otherwise restricted by
|
||||
copyright and certain other rights. Our licenses are
|
||||
irrevocable. Licensors should read and understand the terms
|
||||
and conditions of the license they choose before applying it.
|
||||
Licensors should also secure all rights necessary before
|
||||
applying our licenses so that the public can reuse the
|
||||
material as expected. Licensors should clearly mark any
|
||||
material not subject to the license. This includes other CC-
|
||||
licensed material, or material used under an exception or
|
||||
limitation to copyright. More considerations for licensors:
|
||||
wiki.creativecommons.org/Considerations_for_licensors
|
||||
|
||||
Considerations for the public: By using one of our public
|
||||
licenses, a licensor grants the public permission to use the
|
||||
licensed material under specified terms and conditions. If
|
||||
the licensor's permission is not necessary for any reason--for
|
||||
example, because of any applicable exception or limitation to
|
||||
copyright--then that use is not regulated by the license. Our
|
||||
licenses grant only permissions under copyright and certain
|
||||
other rights that a licensor has authority to grant. Use of
|
||||
the licensed material may still be restricted for other
|
||||
reasons, including because others have copyright or other
|
||||
rights in the material. A licensor may make special requests,
|
||||
such as asking that all changes be marked or described.
|
||||
Although not required by our licenses, you are encouraged to
|
||||
respect those requests where reasonable. More considerations
|
||||
for the public:
|
||||
wiki.creativecommons.org/Considerations_for_licensees
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Attribution-ShareAlike 4.0 International Public
|
||||
License
|
||||
|
||||
By exercising the Licensed Rights (defined below), You accept and agree
|
||||
to be bound by the terms and conditions of this Creative Commons
|
||||
Attribution-ShareAlike 4.0 International Public License ("Public
|
||||
License"). To the extent this Public License may be interpreted as a
|
||||
contract, You are granted the Licensed Rights in consideration of Your
|
||||
acceptance of these terms and conditions, and the Licensor grants You
|
||||
such rights in consideration of benefits the Licensor receives from
|
||||
making the Licensed Material available under these terms and
|
||||
conditions.
|
||||
|
||||
|
||||
Section 1 -- Definitions.
|
||||
|
||||
a. Adapted Material means material subject to Copyright and Similar
|
||||
Rights that is derived from or based upon the Licensed Material
|
||||
and in which the Licensed Material is translated, altered,
|
||||
arranged, transformed, or otherwise modified in a manner requiring
|
||||
permission under the Copyright and Similar Rights held by the
|
||||
Licensor. For purposes of this Public License, where the Licensed
|
||||
Material is a musical work, performance, or sound recording,
|
||||
Adapted Material is always produced where the Licensed Material is
|
||||
synched in timed relation with a moving image.
|
||||
|
||||
b. Adapter's License means the license You apply to Your Copyright
|
||||
and Similar Rights in Your contributions to Adapted Material in
|
||||
accordance with the terms and conditions of this Public License.
|
||||
|
||||
c. BY-SA Compatible License means a license listed at
|
||||
creativecommons.org/compatiblelicenses, approved by Creative
|
||||
Commons as essentially the equivalent of this Public License.
|
||||
|
||||
d. Copyright and Similar Rights means copyright and/or similar rights
|
||||
closely related to copyright including, without limitation,
|
||||
performance, broadcast, sound recording, and Sui Generis Database
|
||||
Rights, without regard to how the rights are labeled or
|
||||
categorized. For purposes of this Public License, the rights
|
||||
specified in Section 2(b)(1)-(2) are not Copyright and Similar
|
||||
Rights.
|
||||
|
||||
e. Effective Technological Measures means those measures that, in the
|
||||
absence of proper authority, may not be circumvented under laws
|
||||
fulfilling obligations under Article 11 of the WIPO Copyright
|
||||
Treaty adopted on December 20, 1996, and/or similar international
|
||||
agreements.
|
||||
|
||||
f. Exceptions and Limitations means fair use, fair dealing, and/or
|
||||
any other exception or limitation to Copyright and Similar Rights
|
||||
that applies to Your use of the Licensed Material.
|
||||
|
||||
g. License Elements means the license attributes listed in the name
|
||||
of a Creative Commons Public License. The License Elements of this
|
||||
Public License are Attribution and ShareAlike.
|
||||
|
||||
h. Licensed Material means the artistic or literary work, database,
|
||||
or other material to which the Licensor applied this Public
|
||||
License.
|
||||
|
||||
i. Licensed Rights means the rights granted to You subject to the
|
||||
terms and conditions of this Public License, which are limited to
|
||||
all Copyright and Similar Rights that apply to Your use of the
|
||||
Licensed Material and that the Licensor has authority to license.
|
||||
|
||||
j. Licensor means the individual(s) or entity(ies) granting rights
|
||||
under this Public License.
|
||||
|
||||
k. Share means to provide material to the public by any means or
|
||||
process that requires permission under the Licensed Rights, such
|
||||
as reproduction, public display, public performance, distribution,
|
||||
dissemination, communication, or importation, and to make material
|
||||
available to the public including in ways that members of the
|
||||
public may access the material from a place and at a time
|
||||
individually chosen by them.
|
||||
|
||||
l. Sui Generis Database Rights means rights other than copyright
|
||||
resulting from Directive 96/9/EC of the European Parliament and of
|
||||
the Council of 11 March 1996 on the legal protection of databases,
|
||||
as amended and/or succeeded, as well as other essentially
|
||||
equivalent rights anywhere in the world.
|
||||
|
||||
m. You means the individual or entity exercising the Licensed Rights
|
||||
under this Public License. Your has a corresponding meaning.
|
||||
|
||||
|
||||
Section 2 -- Scope.
|
||||
|
||||
a. License grant.
|
||||
|
||||
1. Subject to the terms and conditions of this Public License,
|
||||
the Licensor hereby grants You a worldwide, royalty-free,
|
||||
non-sublicensable, non-exclusive, irrevocable license to
|
||||
exercise the Licensed Rights in the Licensed Material to:
|
||||
|
||||
a. reproduce and Share the Licensed Material, in whole or
|
||||
in part; and
|
||||
|
||||
b. produce, reproduce, and Share Adapted Material.
|
||||
|
||||
2. Exceptions and Limitations. For the avoidance of doubt, where
|
||||
Exceptions and Limitations apply to Your use, this Public
|
||||
License does not apply, and You do not need to comply with
|
||||
its terms and conditions.
|
||||
|
||||
3. Term. The term of this Public License is specified in Section
|
||||
6(a).
|
||||
|
||||
4. Media and formats; technical modifications allowed. The
|
||||
Licensor authorizes You to exercise the Licensed Rights in
|
||||
all media and formats whether now known or hereafter created,
|
||||
and to make technical modifications necessary to do so. The
|
||||
Licensor waives and/or agrees not to assert any right or
|
||||
authority to forbid You from making technical modifications
|
||||
necessary to exercise the Licensed Rights, including
|
||||
technical modifications necessary to circumvent Effective
|
||||
Technological Measures. For purposes of this Public License,
|
||||
simply making modifications authorized by this Section 2(a)
|
||||
(4) never produces Adapted Material.
|
||||
|
||||
5. Downstream recipients.
|
||||
|
||||
a. Offer from the Licensor -- Licensed Material. Every
|
||||
recipient of the Licensed Material automatically
|
||||
receives an offer from the Licensor to exercise the
|
||||
Licensed Rights under the terms and conditions of this
|
||||
Public License.
|
||||
|
||||
b. Additional offer from the Licensor -- Adapted Material.
|
||||
Every recipient of Adapted Material from You
|
||||
automatically receives an offer from the Licensor to
|
||||
exercise the Licensed Rights in the Adapted Material
|
||||
under the conditions of the Adapter's License You apply.
|
||||
|
||||
c. No downstream restrictions. You may not offer or impose
|
||||
any additional or different terms or conditions on, or
|
||||
apply any Effective Technological Measures to, the
|
||||
Licensed Material if doing so restricts exercise of the
|
||||
Licensed Rights by any recipient of the Licensed
|
||||
Material.
|
||||
|
||||
6. No endorsement. Nothing in this Public License constitutes or
|
||||
may be construed as permission to assert or imply that You
|
||||
are, or that Your use of the Licensed Material is, connected
|
||||
with, or sponsored, endorsed, or granted official status by,
|
||||
the Licensor or others designated to receive attribution as
|
||||
provided in Section 3(a)(1)(A)(i).
|
||||
|
||||
b. Other rights.
|
||||
|
||||
1. Moral rights, such as the right of integrity, are not
|
||||
licensed under this Public License, nor are publicity,
|
||||
privacy, and/or other similar personality rights; however, to
|
||||
the extent possible, the Licensor waives and/or agrees not to
|
||||
assert any such rights held by the Licensor to the limited
|
||||
extent necessary to allow You to exercise the Licensed
|
||||
Rights, but not otherwise.
|
||||
|
||||
2. Patent and trademark rights are not licensed under this
|
||||
Public License.
|
||||
|
||||
3. To the extent possible, the Licensor waives any right to
|
||||
collect royalties from You for the exercise of the Licensed
|
||||
Rights, whether directly or through a collecting society
|
||||
under any voluntary or waivable statutory or compulsory
|
||||
licensing scheme. In all other cases the Licensor expressly
|
||||
reserves any right to collect such royalties.
|
||||
|
||||
|
||||
Section 3 -- License Conditions.
|
||||
|
||||
Your exercise of the Licensed Rights is expressly made subject to the
|
||||
following conditions.
|
||||
|
||||
a. Attribution.
|
||||
|
||||
1. If You Share the Licensed Material (including in modified
|
||||
form), You must:
|
||||
|
||||
a. retain the following if it is supplied by the Licensor
|
||||
with the Licensed Material:
|
||||
|
||||
i. identification of the creator(s) of the Licensed
|
||||
Material and any others designated to receive
|
||||
attribution, in any reasonable manner requested by
|
||||
the Licensor (including by pseudonym if
|
||||
designated);
|
||||
|
||||
ii. a copyright notice;
|
||||
|
||||
iii. a notice that refers to this Public License;
|
||||
|
||||
iv. a notice that refers to the disclaimer of
|
||||
warranties;
|
||||
|
||||
v. a URI or hyperlink to the Licensed Material to the
|
||||
extent reasonably practicable;
|
||||
|
||||
b. indicate if You modified the Licensed Material and
|
||||
retain an indication of any previous modifications; and
|
||||
|
||||
c. indicate the Licensed Material is licensed under this
|
||||
Public License, and include the text of, or the URI or
|
||||
hyperlink to, this Public License.
|
||||
|
||||
2. You may satisfy the conditions in Section 3(a)(1) in any
|
||||
reasonable manner based on the medium, means, and context in
|
||||
which You Share the Licensed Material. For example, it may be
|
||||
reasonable to satisfy the conditions by providing a URI or
|
||||
hyperlink to a resource that includes the required
|
||||
information.
|
||||
|
||||
3. If requested by the Licensor, You must remove any of the
|
||||
information required by Section 3(a)(1)(A) to the extent
|
||||
reasonably practicable.
|
||||
|
||||
b. ShareAlike.
|
||||
|
||||
In addition to the conditions in Section 3(a), if You Share
|
||||
Adapted Material You produce, the following conditions also apply.
|
||||
|
||||
1. The Adapter's License You apply must be a Creative Commons
|
||||
license with the same License Elements, this version or
|
||||
later, or a BY-SA Compatible License.
|
||||
|
||||
2. You must include the text of, or the URI or hyperlink to, the
|
||||
Adapter's License You apply. You may satisfy this condition
|
||||
in any reasonable manner based on the medium, means, and
|
||||
context in which You Share Adapted Material.
|
||||
|
||||
3. You may not offer or impose any additional or different terms
|
||||
or conditions on, or apply any Effective Technological
|
||||
Measures to, Adapted Material that restrict exercise of the
|
||||
rights granted under the Adapter's License You apply.
|
||||
|
||||
|
||||
Section 4 -- Sui Generis Database Rights.
|
||||
|
||||
Where the Licensed Rights include Sui Generis Database Rights that
|
||||
apply to Your use of the Licensed Material:
|
||||
|
||||
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
|
||||
to extract, reuse, reproduce, and Share all or a substantial
|
||||
portion of the contents of the database;
|
||||
|
||||
b. if You include all or a substantial portion of the database
|
||||
contents in a database in which You have Sui Generis Database
|
||||
Rights, then the database in which You have Sui Generis Database
|
||||
Rights (but not its individual contents) is Adapted Material,
|
||||
including for purposes of Section 3(b); and
|
||||
|
||||
c. You must comply with the conditions in Section 3(a) if You Share
|
||||
all or a substantial portion of the contents of the database.
|
||||
|
||||
For the avoidance of doubt, this Section 4 supplements and does not
|
||||
replace Your obligations under this Public License where the Licensed
|
||||
Rights include other Copyright and Similar Rights.
|
||||
|
||||
|
||||
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
|
||||
|
||||
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
|
||||
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
|
||||
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
|
||||
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
|
||||
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
|
||||
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
|
||||
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
|
||||
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
|
||||
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
|
||||
|
||||
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
|
||||
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
|
||||
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
|
||||
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
|
||||
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
|
||||
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
|
||||
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
|
||||
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
|
||||
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
|
||||
|
||||
c. The disclaimer of warranties and limitation of liability provided
|
||||
above shall be interpreted in a manner that, to the extent
|
||||
possible, most closely approximates an absolute disclaimer and
|
||||
waiver of all liability.
|
||||
|
||||
|
||||
Section 6 -- Term and Termination.
|
||||
|
||||
a. This Public License applies for the term of the Copyright and
|
||||
Similar Rights licensed here. However, if You fail to comply with
|
||||
this Public License, then Your rights under this Public License
|
||||
terminate automatically.
|
||||
|
||||
b. Where Your right to use the Licensed Material has terminated under
|
||||
Section 6(a), it reinstates:
|
||||
|
||||
1. automatically as of the date the violation is cured, provided
|
||||
it is cured within 30 days of Your discovery of the
|
||||
violation; or
|
||||
|
||||
2. upon express reinstatement by the Licensor.
|
||||
|
||||
For the avoidance of doubt, this Section 6(b) does not affect any
|
||||
right the Licensor may have to seek remedies for Your violations
|
||||
of this Public License.
|
||||
|
||||
c. For the avoidance of doubt, the Licensor may also offer the
|
||||
Licensed Material under separate terms or conditions or stop
|
||||
distributing the Licensed Material at any time; however, doing so
|
||||
will not terminate this Public License.
|
||||
|
||||
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
|
||||
License.
|
||||
|
||||
|
||||
Section 7 -- Other Terms and Conditions.
|
||||
|
||||
a. The Licensor shall not be bound by any additional or different
|
||||
terms or conditions communicated by You unless expressly agreed.
|
||||
|
||||
b. Any arrangements, understandings, or agreements regarding the
|
||||
Licensed Material not stated herein are separate from and
|
||||
independent of the terms and conditions of this Public License.
|
||||
|
||||
|
||||
Section 8 -- Interpretation.
|
||||
|
||||
a. For the avoidance of doubt, this Public License does not, and
|
||||
shall not be interpreted to, reduce, limit, restrict, or impose
|
||||
conditions on any use of the Licensed Material that could lawfully
|
||||
be made without permission under this Public License.
|
||||
|
||||
b. To the extent possible, if any provision of this Public License is
|
||||
deemed unenforceable, it shall be automatically reformed to the
|
||||
minimum extent necessary to make it enforceable. If the provision
|
||||
cannot be reformed, it shall be severed from this Public License
|
||||
without affecting the enforceability of the remaining terms and
|
||||
conditions.
|
||||
|
||||
c. No term or condition of this Public License will be waived and no
|
||||
failure to comply consented to unless expressly agreed to by the
|
||||
Licensor.
|
||||
|
||||
d. Nothing in this Public License constitutes or may be interpreted
|
||||
as a limitation upon, or waiver of, any privileges and immunities
|
||||
that apply to the Licensor or You, including from the legal
|
||||
processes of any jurisdiction or authority.
|
||||
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons is not a party to its public
|
||||
licenses. Notwithstanding, Creative Commons may elect to apply one of
|
||||
its public licenses to material it publishes and in those instances
|
||||
will be considered the “Licensor.” The text of the Creative Commons
|
||||
public licenses is dedicated to the public domain under the CC0 Public
|
||||
Domain Dedication. Except for the limited purpose of indicating that
|
||||
material is shared under a Creative Commons public license or as
|
||||
otherwise permitted by the Creative Commons policies published at
|
||||
creativecommons.org/policies, Creative Commons does not authorize the
|
||||
use of the trademark "Creative Commons" or any other trademark or logo
|
||||
of Creative Commons without its prior written consent including,
|
||||
without limitation, in connection with any unauthorized modifications
|
||||
to any of its public licenses or any other arrangements,
|
||||
understandings, or agreements concerning use of licensed material. For
|
||||
the avoidance of doubt, this paragraph does not form part of the
|
||||
public licenses.
|
||||
|
||||
Creative Commons may be contacted at creativecommons.org.
|
177
case/README.md
Normal file
@@ -0,0 +1,177 @@
|
||||
# SuperSensor 2.x Case
|
||||
|
||||
This is a 3D-printable case for the SuperSensor 2.x all-in-one voice, motion,
|
||||
presence, temperature/humidity/air quality, and light sensor.
|
||||
|
||||
This case provides a convenient way to cover up the SuperSensor's PCB, either
|
||||
for aesthetics or to help protect it from harsh environments.
|
||||
|
||||
You can [tinker the design on TinkerCAD here](https://www.tinkercad.com/things/1HT3fyNbln0-supersensor-case).
|
||||
The case design and images in this folder are licensed under the Creative Commons
|
||||
Attribution-ShareAlike (BY-SA) 4.0 license.
|
||||
|
||||
## Printing
|
||||
|
||||
Provided here are 5 `.obj` CAD files designed for slicing and printing with
|
||||
any slicer software and 3D printer.
|
||||
|
||||
### `body.obj`
|
||||
|
||||
This is the main body of the case which houses the PCB. It includes an opening
|
||||
for the insertion of a USB-C cable of "normal" size, which should fit most cables.
|
||||
|
||||
This part should be printed in a solid, durable material of any colour you wish.
|
||||
|
||||
### `face.obj`
|
||||
|
||||
This is the front face of the case. It clips into the body with 4 triangular
|
||||
grip clips, and has 5 openings:
|
||||
* A large rectangle for the insert below.
|
||||
* A large circle for the PIR and am312 extension tube below.
|
||||
* A small flush hole for the TSL2591 light sensor.
|
||||
* A small funneled hole for the SGP41 air quality sensor.
|
||||
* A small funneled hole for the SHT45 temperature/humidity sensor.
|
||||
|
||||
**NOTE**: This design can affect the baseline readings of these sensors!
|
||||
Specifically, the TSL will report much lower ambient light levels (up to 30 lux)
|
||||
unless light is directly facing it; and the SHT45 will hover about 6 degrees
|
||||
higher than the exposed PCB would from my testing. Take these into account in
|
||||
your usage!
|
||||
|
||||
This part should be printed in a solid, durable material of any colour you wish.
|
||||
|
||||
### `insert.obj`
|
||||
|
||||
This insert fits into the large rectangle in the face, and provides a diffuser
|
||||
for the feedback/status LEDs, including an opening for the INA microphone. It
|
||||
is inserted into the face separately during assembly, though a multi-material
|
||||
printer could concievably print it into the face during printing.
|
||||
|
||||
This part should be printed in a solid, durable material in **a natural or transluscent** colour (it must let light through).
|
||||
|
||||
### `am312-tube.obj`
|
||||
|
||||
This round tube provides additional buffering for the AM312 over the face, extending
|
||||
it by 8mm to completely cover the AM312 body. It attaches to the face over the large
|
||||
circular hol separately during assembly.
|
||||
|
||||
This part should be printed in a solid, durable material in any colour you wish.
|
||||
|
||||
### `usb-extension.obj` (optional)
|
||||
|
||||
This square tube provides additional coverage of the USB cable opening for situations
|
||||
where that may be needed, either for "weatherproofing", cable management, or mounting.
|
||||
It attaches over the opening in the body and should fit most cables. Note that USB
|
||||
insertion may be harder with this on so consider that carefully during cable selection;
|
||||
a long boot cable is a plus here.
|
||||
|
||||
This part should be printed in a solid, durable material in any colour you wish.
|
||||
|
||||
## Assembly
|
||||
|
||||
To begin, print the parts above as indicated; default slicer settings should be sufficient.
|
||||
We will exclude the USB cable opening extension for this assembly, but its installation
|
||||
is straightforward.
|
||||
|
||||
Lay out the parts; you will need:
|
||||
|
||||
* The body, face, insert, and AM312 tube parts.
|
||||
* Superglue
|
||||
* A toothpick (if not using a precision superglue applicator)
|
||||
* A hard, flat surface (I use a vice)
|
||||
|
||||

|
||||
|
||||
### Face
|
||||
|
||||
1. Place the face face-down (clips up), and place dabs of superglue at the corners of the
|
||||
insert openings.
|
||||
|
||||

|
||||
|
||||
2. Spread the superglue along the inner edges with the toothpick; or, combine 2+3 by using
|
||||
a precision superglue applicator. You need very little glue here; avoid extra ooze!
|
||||
|
||||

|
||||
|
||||
3. Firmly place the insert face-down into the hole; the overlap edges should match.
|
||||
|
||||

|
||||
|
||||
4. Apply firm pressure to both sides of the insert with your thumbs, a vice, or another
|
||||
pressing object, until the glue can set up (15-30 seconds).
|
||||
|
||||

|
||||
|
||||
5. Flip over the face; the insert should now be solidly affixed. Clean up any oozing superglue
|
||||
with a paper towel or lint-free rag.
|
||||
|
||||

|
||||
|
||||
6. Place a small amount of superglue on your toothpick tip; if using a precision superglue
|
||||
applicator, skip this step.
|
||||
|
||||

|
||||
|
||||
7. Gently spread the superglue around the circular opening (or apply using a precision superglue
|
||||
applicator); you want the bead to be no more than 1mm wide to avoid ooze.
|
||||
|
||||

|
||||
|
||||
8. Line up the AM312 tube, and firmly press it down to seal. Clean up any oozing superglue
|
||||
with a paper towel or lint-free rag.
|
||||
|
||||

|
||||
|
||||
You will now have a completed face assembly and are ready to install the actual SuperSensor.
|
||||
|
||||

|
||||
|
||||
### Body
|
||||
|
||||
1. Gently insert the SuperSensor board into the case body, lining it up with the four standoffs.
|
||||
The ESP32 should b firmly sitting on the bottom (it should require no force).
|
||||
|
||||

|
||||
|
||||
You can verify that the USB plug is sitting flush on the base.
|
||||
|
||||

|
||||
|
||||
2. Remove the top cap of the AM312.
|
||||
|
||||
3. Place the face over the AM312.
|
||||
|
||||

|
||||
|
||||
4. Line up the clips on one side (I prefer the left). Then using a gentle squeezing motion, apply
|
||||
pressure to the sides of the case on the right side while also applying lateral pressure on
|
||||
the face towards the inserted clips. This picture is a one-handed demonstration, applying a
|
||||
squeezing pressure between my thumb and middle finger and a downwards pressure with my index
|
||||
finger to provide force; using two hands is advised.
|
||||
|
||||

|
||||
|
||||
5. While doing the previous step, ensure that the 3 sensor holes are lined up with their corresponding sensors.
|
||||
|
||||

|
||||
|
||||
6. Press the face into the body so that all 4 clips are making contact.
|
||||
|
||||

|
||||
|
||||
7. Reinstall the top cap of the AM312; it should have a snug fit against the tube.
|
||||
|
||||
You now have an assembled case!
|
||||
|
||||

|
||||
|
||||
As a further step, consider placing a line of tape around the face-body joint. The locking clip
|
||||
design was made with printing in mind, and does have some play here.
|
||||
|
||||
## Installation
|
||||
|
||||
You may either mount the SuperSensor by its USB plug (as with a bare board design), or by attaching
|
||||
a mounting piece to the case. Enjoy your newly-enclosed SuperSensor with diffused status LEDs!
|
||||
|
||||

|
592
case/am312-tube.obj
Normal file
@@ -0,0 +1,592 @@
|
||||
# Object Export From Tinkercad Server 2015
|
||||
|
||||
mtllib obj.mtl
|
||||
|
||||
o obj_0
|
||||
v 25.003 -60.5 0
|
||||
v 24.947 -61.349 0
|
||||
v 12.219 -58.817 0
|
||||
v 12.053 -59.651 0
|
||||
v 25.003 -60.5 8
|
||||
v 24.947 -61.349 8
|
||||
v 12.492 -58.012 0
|
||||
v 24.781 -62.183 0
|
||||
v 12.869 -57.249 0
|
||||
v 12.492 -58.012 8
|
||||
v 24.508 -62.988 0
|
||||
v 12.869 -57.249 8
|
||||
v 24.781 -62.183 8
|
||||
v 13.341 -56.542 0
|
||||
v 24.131 -63.751 0
|
||||
v 13.341 -56.542 8
|
||||
v 24.45 -65.066 0
|
||||
v 24.995 -64.25 0
|
||||
v 24.995 -64.25 8
|
||||
v 24.508 -62.988 8
|
||||
v 24.45 -65.066 8
|
||||
v 13.902 -55.902 8
|
||||
v 23.659 -64.458 0
|
||||
v 24.781 -58.817 0
|
||||
v 24.781 -58.817 8
|
||||
v 24.508 -58.012 8
|
||||
v 24.508 -58.012 0
|
||||
v 13.902 -55.902 0
|
||||
v 23.098 -65.098 0
|
||||
v 24.131 -63.751 8
|
||||
v 14.75 -66.995 0
|
||||
v 14.75 -66.995 8
|
||||
v 24.947 -59.651 0
|
||||
v 24.947 -59.651 8
|
||||
v 13.934 -54.55 8
|
||||
v 13.197 -55.197 8
|
||||
v 12.55 -55.934 8
|
||||
v 12.005 -56.75 8
|
||||
v 25.429 -63.37 0
|
||||
v 23.659 -64.458 8
|
||||
v 25.429 -63.37 8
|
||||
v 25.744 -62.441 0
|
||||
v 25.744 -62.441 8
|
||||
v 12.005 -56.75 0
|
||||
v 23.098 -65.098 8
|
||||
v 12.55 -55.934 0
|
||||
v 22.25 -54.005 0
|
||||
v 23.803 -65.803 0
|
||||
v 22.25 -54.005 8
|
||||
v 13.197 -55.197 0
|
||||
v 23.066 -66.45 0
|
||||
v 15.63 -67.429 0
|
||||
v 13.934 -54.55 0
|
||||
v 15.63 -67.429 8
|
||||
v 25.936 -61.479 0
|
||||
v 25.936 -61.479 8
|
||||
v 11.571 -57.63 8
|
||||
v 11.256 -58.559 8
|
||||
v 11.064 -59.521 8
|
||||
v 26 -60.5 0
|
||||
v 26 -60.5 8
|
||||
v 16.559 -67.744 0
|
||||
v 16.559 -67.744 8
|
||||
v 21.37 -53.571 0
|
||||
v 21.37 -53.571 8
|
||||
v 11.064 -59.521 0
|
||||
v 23.098 -55.902 0
|
||||
v 11.256 -58.559 0
|
||||
v 25.936 -59.521 0
|
||||
v 11.571 -57.63 0
|
||||
v 25.936 -59.521 8
|
||||
v 20.441 -53.256 0
|
||||
v 20.441 -53.256 8
|
||||
v 13.902 -65.098 8
|
||||
v 25.744 -58.559 0
|
||||
v 19.479 -53.064 0
|
||||
v 25.744 -58.559 8
|
||||
v 19.479 -53.064 8
|
||||
v 23.066 -66.45 8
|
||||
v 23.803 -65.803 8
|
||||
v 13.902 -65.098 0
|
||||
v 18.5 -53 0
|
||||
v 18.5 -53 8
|
||||
v 23.659 -56.542 0
|
||||
v 25.429 -57.63 0
|
||||
v 25.429 -57.63 8
|
||||
v 17.521 -53.064 0
|
||||
v 17.521 -53.064 8
|
||||
v 13.341 -64.458 8
|
||||
v 13.341 -64.458 0
|
||||
v 23.098 -55.902 8
|
||||
v 16.559 -53.256 0
|
||||
v 24.995 -56.75 0
|
||||
v 16.559 -53.256 8
|
||||
v 24.995 -56.75 8
|
||||
v 24.131 -57.249 0
|
||||
v 12.869 -63.751 8
|
||||
v 15.63 -53.571 0
|
||||
v 23.659 -56.542 8
|
||||
v 15.63 -53.571 8
|
||||
v 12.869 -63.751 0
|
||||
v 23.066 -54.55 0
|
||||
v 24.45 -55.934 0
|
||||
v 24.45 -55.934 8
|
||||
v 14.75 -54.005 0
|
||||
v 14.75 -54.005 8
|
||||
v 12.492 -62.988 8
|
||||
v 24.131 -57.249 8
|
||||
v 12.053 -59.651 8
|
||||
v 12.492 -62.988 0
|
||||
v 13.934 -66.45 8
|
||||
v 13.934 -66.45 0
|
||||
v 23.803 -55.197 0
|
||||
v 12.219 -58.817 8
|
||||
v 12.219 -62.183 8
|
||||
v 13.197 -65.803 8
|
||||
v 12.219 -62.183 0
|
||||
v 23.066 -54.55 8
|
||||
v 13.197 -65.803 0
|
||||
v 23.803 -55.197 8
|
||||
v 12.053 -61.349 8
|
||||
v 12.55 -65.066 8
|
||||
v 12.053 -61.349 0
|
||||
v 14.542 -55.341 0
|
||||
v 14.542 -55.341 8
|
||||
v 12.55 -65.066 0
|
||||
v 11.998 -60.5 8
|
||||
v 15.249 -54.869 0
|
||||
v 11.998 -60.5 0
|
||||
v 15.249 -54.869 8
|
||||
v 12.005 -64.25 0
|
||||
v 12.005 -64.25 8
|
||||
v 17.651 -66.947 0
|
||||
v 16.012 -54.492 0
|
||||
v 18.5 -67.003 0
|
||||
v 16.012 -54.492 8
|
||||
v 18.5 -67.003 8
|
||||
v 17.651 -66.947 8
|
||||
v 16.817 -66.781 0
|
||||
v 16.817 -54.219 0
|
||||
v 16.817 -54.219 8
|
||||
v 20.441 -67.744 0
|
||||
v 20.441 -67.744 8
|
||||
v 16.817 -66.781 8
|
||||
v 16.012 -66.508 0
|
||||
v 17.651 -54.053 0
|
||||
v 17.651 -54.053 8
|
||||
v 16.012 -66.508 8
|
||||
v 21.37 -67.429 0
|
||||
v 21.37 -67.429 8
|
||||
v 15.249 -66.131 0
|
||||
v 18.5 -53.998 0
|
||||
v 18.5 -53.998 8
|
||||
v 15.249 -66.131 8
|
||||
v 22.25 -66.995 0
|
||||
v 22.25 -66.995 8
|
||||
v 14.542 -65.659 0
|
||||
v 19.349 -54.053 0
|
||||
v 19.349 -54.053 8
|
||||
v 14.542 -65.659 8
|
||||
v 20.183 -54.219 0
|
||||
v 20.183 -54.219 8
|
||||
v 20.988 -54.492 0
|
||||
v 20.988 -54.492 8
|
||||
v 11 -60.5 0
|
||||
v 11 -60.5 8
|
||||
v 22.458 -65.659 0
|
||||
v 21.751 -54.869 0
|
||||
v 21.751 -54.869 8
|
||||
v 11.064 -61.479 0
|
||||
v 11.064 -61.479 8
|
||||
v 22.458 -65.659 8
|
||||
v 21.751 -66.131 0
|
||||
v 22.458 -55.341 0
|
||||
v 22.458 -55.341 8
|
||||
v 11.256 -62.441 0
|
||||
v 11.256 -62.441 8
|
||||
v 21.751 -66.131 8
|
||||
v 11.571 -63.37 0
|
||||
v 11.571 -63.37 8
|
||||
v 20.988 -66.508 0
|
||||
v 20.988 -66.508 8
|
||||
v 20.183 -66.781 0
|
||||
v 20.183 -66.781 8
|
||||
v 19.349 -66.947 0
|
||||
v 19.349 -66.947 8
|
||||
v 17.521 -67.936 8
|
||||
v 18.5 -68 0
|
||||
v 17.521 -67.936 0
|
||||
v 18.5 -68 8
|
||||
v 19.479 -67.936 8
|
||||
v 19.479 -67.936 0
|
||||
# 192 vertices
|
||||
|
||||
g group_0_16089887
|
||||
|
||||
usemtl color_16089887
|
||||
s 0
|
||||
|
||||
f 1 33 69
|
||||
f 2 1 55
|
||||
f 12 38 10
|
||||
f 13 20 43
|
||||
f 8 2 42
|
||||
f 16 38 12
|
||||
f 17 18 19
|
||||
f 17 19 21
|
||||
f 35 36 22
|
||||
f 7 3 68
|
||||
f 11 18 15
|
||||
f 24 25 26
|
||||
f 24 26 27
|
||||
f 33 34 25
|
||||
f 33 25 24
|
||||
f 39 41 18
|
||||
f 19 18 41
|
||||
f 38 16 37
|
||||
f 36 37 22
|
||||
f 22 37 16
|
||||
f 35 125 106
|
||||
f 30 19 20
|
||||
f 1 34 33
|
||||
f 52 54 32
|
||||
f 52 32 31
|
||||
f 39 42 43
|
||||
f 39 43 41
|
||||
f 40 19 30
|
||||
f 42 55 56
|
||||
f 42 56 43
|
||||
f 44 46 14
|
||||
f 28 14 46
|
||||
f 46 50 28
|
||||
f 28 50 53
|
||||
f 47 64 65
|
||||
f 47 65 49
|
||||
f 23 15 18
|
||||
f 18 17 23
|
||||
f 29 23 17
|
||||
f 29 17 48
|
||||
f 29 48 51
|
||||
f 114 10 58
|
||||
f 59 109 58
|
||||
f 55 60 61
|
||||
f 55 61 56
|
||||
f 62 63 54
|
||||
f 62 54 52
|
||||
f 60 69 71
|
||||
f 60 71 61
|
||||
f 64 72 73
|
||||
f 64 73 65
|
||||
f 14 9 44
|
||||
f 9 7 44
|
||||
f 70 44 7
|
||||
f 68 70 7
|
||||
f 3 4 68
|
||||
f 66 68 4
|
||||
f 72 76 78
|
||||
f 72 78 73
|
||||
f 69 75 77
|
||||
f 69 77 71
|
||||
f 76 82 83
|
||||
f 76 83 78
|
||||
f 79 80 45
|
||||
f 80 21 45
|
||||
f 40 45 21
|
||||
f 40 21 19
|
||||
f 70 57 44
|
||||
f 38 44 57
|
||||
f 75 85 86
|
||||
f 75 86 77
|
||||
f 82 87 88
|
||||
f 82 88 83
|
||||
f 89 122 74
|
||||
f 70 68 58
|
||||
f 70 58 57
|
||||
f 87 92 94
|
||||
f 87 94 88
|
||||
f 68 66 59
|
||||
f 68 59 58
|
||||
f 113 103 67
|
||||
f 102 113 67
|
||||
f 97 132 89
|
||||
f 92 98 100
|
||||
f 92 100 94
|
||||
f 99 104 91
|
||||
f 85 93 95
|
||||
f 85 95 86
|
||||
f 112 119 81
|
||||
f 84 67 103
|
||||
f 103 93 84
|
||||
f 103 104 93
|
||||
f 180 132 107
|
||||
f 32 160 111
|
||||
f 108 95 99
|
||||
f 127 129 109
|
||||
f 4 109 129
|
||||
f 119 126 81
|
||||
f 90 81 126
|
||||
f 98 105 106
|
||||
f 98 106 100
|
||||
f 96 84 93
|
||||
f 93 104 95
|
||||
f 3 114 109
|
||||
f 3 109 4
|
||||
f 115 177 107
|
||||
f 111 74 116
|
||||
f 26 95 108
|
||||
f 169 175 49
|
||||
f 35 106 105
|
||||
f 126 131 90
|
||||
f 101 90 131
|
||||
f 27 96 93
|
||||
f 93 85 27
|
||||
f 7 10 114
|
||||
f 7 114 3
|
||||
f 25 34 77
|
||||
f 121 177 115
|
||||
f 116 74 122
|
||||
f 104 103 120
|
||||
f 113 120 103
|
||||
f 9 12 10
|
||||
f 9 10 7
|
||||
f 22 28 125
|
||||
f 124 125 28
|
||||
f 110 101 131
|
||||
f 131 179 110
|
||||
f 85 75 27
|
||||
f 24 27 75
|
||||
f 120 91 104
|
||||
f 179 176 110
|
||||
f 117 110 176
|
||||
f 97 107 132
|
||||
f 122 89 132
|
||||
f 14 16 12
|
||||
f 14 12 9
|
||||
f 104 99 95
|
||||
f 34 5 71
|
||||
f 128 130 125
|
||||
f 128 125 124
|
||||
f 118 113 102
|
||||
f 28 22 16
|
||||
f 28 16 14
|
||||
f 134 136 130
|
||||
f 134 130 128
|
||||
f 113 118 120
|
||||
f 135 189 133
|
||||
f 90 89 74
|
||||
f 90 74 81
|
||||
f 140 141 136
|
||||
f 140 136 134
|
||||
f 49 102 47
|
||||
f 101 97 89
|
||||
f 101 89 90
|
||||
f 142 143 191
|
||||
f 142 191 192
|
||||
f 146 147 141
|
||||
f 146 141 140
|
||||
f 5 6 56
|
||||
f 6 13 43
|
||||
f 41 43 20
|
||||
f 41 20 19
|
||||
f 43 56 6
|
||||
f 56 61 5
|
||||
f 61 71 5
|
||||
f 71 77 34
|
||||
f 26 25 77
|
||||
f 77 86 26
|
||||
f 95 26 86
|
||||
f 102 49 118
|
||||
f 149 150 143
|
||||
f 149 143 142
|
||||
f 110 107 97
|
||||
f 110 97 101
|
||||
f 139 62 145
|
||||
f 152 153 147
|
||||
f 152 147 146
|
||||
f 34 1 5
|
||||
f 154 32 148
|
||||
f 155 156 150
|
||||
f 155 150 149
|
||||
f 130 106 125
|
||||
f 158 159 153
|
||||
f 158 153 152
|
||||
f 117 115 107
|
||||
f 117 107 110
|
||||
f 2 6 5
|
||||
f 2 5 1
|
||||
f 160 32 154
|
||||
f 22 125 35
|
||||
f 161 162 159
|
||||
f 161 159 158
|
||||
f 123 121 115
|
||||
f 123 115 117
|
||||
f 8 13 6
|
||||
f 8 6 2
|
||||
f 156 155 51
|
||||
f 151 145 31
|
||||
f 112 157 31
|
||||
f 151 31 157
|
||||
f 81 157 112
|
||||
f 163 164 162
|
||||
f 163 162 161
|
||||
f 121 123 129
|
||||
f 121 129 127
|
||||
f 11 20 13
|
||||
f 11 13 8
|
||||
f 74 111 160
|
||||
f 32 54 148
|
||||
f 54 63 148
|
||||
f 166 59 165
|
||||
f 66 165 59
|
||||
f 147 94 141
|
||||
f 141 94 136
|
||||
f 29 51 167
|
||||
f 168 169 164
|
||||
f 168 164 163
|
||||
f 15 30 20
|
||||
f 15 20 11
|
||||
f 166 165 170
|
||||
f 166 170 171
|
||||
f 153 83 147
|
||||
f 130 136 106
|
||||
f 174 175 169
|
||||
f 174 169 168
|
||||
f 170 176 177
|
||||
f 170 177 171
|
||||
f 23 40 30
|
||||
f 23 30 15
|
||||
f 178 156 172
|
||||
f 133 138 137
|
||||
f 133 137 135
|
||||
f 176 179 180
|
||||
f 176 180 177
|
||||
f 51 155 167
|
||||
f 29 45 40
|
||||
f 29 40 23
|
||||
f 67 91 175
|
||||
f 67 175 174
|
||||
f 150 156 182
|
||||
f 45 172 79
|
||||
f 139 144 138
|
||||
f 139 138 133
|
||||
f 180 131 132
|
||||
f 105 53 35
|
||||
f 173 167 155
|
||||
f 179 131 180
|
||||
f 53 50 36
|
||||
f 53 36 35
|
||||
f 184 143 182
|
||||
f 79 172 156
|
||||
f 50 46 37
|
||||
f 50 37 36
|
||||
f 145 148 144
|
||||
f 145 144 139
|
||||
f 186 143 184
|
||||
f 46 44 38
|
||||
f 46 38 37
|
||||
f 155 149 181
|
||||
f 181 173 155
|
||||
f 175 91 118
|
||||
f 91 67 84
|
||||
f 91 84 99
|
||||
f 151 154 148
|
||||
f 151 148 145
|
||||
f 131 126 122
|
||||
f 131 122 132
|
||||
f 190 191 137
|
||||
f 178 182 156
|
||||
f 183 181 142
|
||||
f 149 142 181
|
||||
f 99 84 96
|
||||
f 99 96 108
|
||||
f 169 49 164
|
||||
f 120 118 91
|
||||
f 118 49 175
|
||||
f 65 164 49
|
||||
f 157 160 154
|
||||
f 157 154 151
|
||||
f 75 69 33
|
||||
f 33 24 75
|
||||
f 69 60 1
|
||||
f 60 55 1
|
||||
f 55 42 2
|
||||
f 11 8 42
|
||||
f 42 39 11
|
||||
f 18 11 39
|
||||
f 108 96 27
|
||||
f 108 27 26
|
||||
f 126 119 116
|
||||
f 126 116 122
|
||||
f 124 28 53
|
||||
f 81 74 160
|
||||
f 81 160 157
|
||||
f 53 105 124
|
||||
f 128 124 105
|
||||
f 116 119 111
|
||||
f 112 111 119
|
||||
f 138 144 63
|
||||
f 144 148 63
|
||||
f 63 187 138
|
||||
f 137 138 187
|
||||
f 187 190 137
|
||||
f 150 182 143
|
||||
f 134 128 105
|
||||
f 52 31 145
|
||||
f 62 52 145
|
||||
f 62 139 133
|
||||
f 142 192 185
|
||||
f 185 183 142
|
||||
f 185 192 135
|
||||
f 188 135 192
|
||||
f 94 147 88
|
||||
f 100 136 94
|
||||
f 106 136 100
|
||||
f 88 147 83
|
||||
f 83 153 159
|
||||
f 162 73 159
|
||||
f 65 73 164
|
||||
f 162 164 73
|
||||
f 73 78 159
|
||||
f 83 159 78
|
||||
f 45 29 167
|
||||
f 45 167 172
|
||||
f 105 98 134
|
||||
f 98 92 134
|
||||
f 140 134 92
|
||||
f 127 109 166
|
||||
f 121 127 166
|
||||
f 166 171 121
|
||||
f 177 121 171
|
||||
f 180 107 177
|
||||
f 123 117 176
|
||||
f 176 170 123
|
||||
f 170 165 123
|
||||
f 129 123 165
|
||||
f 4 129 165
|
||||
f 4 165 66
|
||||
f 172 167 173
|
||||
f 172 173 178
|
||||
f 62 133 189
|
||||
f 189 135 188
|
||||
f 114 58 109
|
||||
f 59 166 109
|
||||
f 161 72 163
|
||||
f 143 186 191
|
||||
f 186 137 191
|
||||
f 111 112 32
|
||||
f 31 32 112
|
||||
f 38 57 10
|
||||
f 57 58 10
|
||||
f 178 173 181
|
||||
f 178 181 182
|
||||
f 51 79 156
|
||||
f 168 163 47
|
||||
f 174 168 47
|
||||
f 47 102 174
|
||||
f 67 174 102
|
||||
f 51 48 80
|
||||
f 51 80 79
|
||||
f 182 181 183
|
||||
f 182 183 184
|
||||
f 48 17 21
|
||||
f 48 21 80
|
||||
f 64 47 163
|
||||
f 158 72 161
|
||||
f 87 82 146
|
||||
f 146 140 92
|
||||
f 92 87 146
|
||||
f 152 146 82
|
||||
f 158 152 82
|
||||
f 82 76 158
|
||||
f 72 158 76
|
||||
f 64 163 72
|
||||
f 184 183 185
|
||||
f 184 185 186
|
||||
f 186 185 135
|
||||
f 186 135 137
|
||||
f 190 188 192
|
||||
f 190 192 191
|
||||
f 63 62 187
|
||||
f 189 187 62
|
||||
f 188 190 187
|
||||
f 188 187 189
|
||||
# 384 faces
|
||||
|
||||
#end of obj_0
|
||||
|
2953
case/body.obj
Normal file
1133
case/face.obj
Normal file
361
case/insert.obj
Normal file
@@ -0,0 +1,361 @@
|
||||
# Object Export From Tinkercad Server 2015
|
||||
|
||||
mtllib obj.mtl
|
||||
|
||||
o obj_0
|
||||
v 35.425 -3.7 0.32
|
||||
v 35.425 -3.7 0
|
||||
v 35.425 -14.1 0
|
||||
v 35.425 -14.1 0.32
|
||||
v 60.0646 -9.8708 0
|
||||
v 60.1961 -9.9358 0
|
||||
v 60.0646 -7.9292 0
|
||||
v 36.625 -12.9 0.32
|
||||
v 59.9425 -8.0104 0
|
||||
v 36.625 -4.9 0.32
|
||||
v 59.8322 -8.1072 0
|
||||
v 59.9425 -9.7896 0
|
||||
v 62.0396 -10.3146 1.32
|
||||
v 36.625 -4.9 1.32
|
||||
v 60.1961 -7.8642 0
|
||||
v 61.8428 -10.4874 1.32
|
||||
v 60.335 -9.9828 0
|
||||
v 62.2124 -10.1178 1.32
|
||||
v 60.4789 -10.0114 0
|
||||
v 36.625 -12.9 1.32
|
||||
v 85.825 -14.1 0.32
|
||||
v 85.825 -14.1 0
|
||||
v 85.825 -3.7 0
|
||||
v 60.625 -10.0214 0
|
||||
v 85.825 -3.7 0.32
|
||||
v 84.625 -4.9 0.32
|
||||
v 84.625 -12.9 0.32
|
||||
v 62.628 -3.7 0
|
||||
v 62.3573 -9.9 1.32
|
||||
v 62.4732 -9.6652 1.32
|
||||
v 84.625 -4.9 1.32
|
||||
v 84.625 -12.9 1.32
|
||||
v 62.608 -9.1607 1.32
|
||||
v 62.5571 -9.4175 1.32
|
||||
v 60.7711 -10.0114 0
|
||||
v 62.626 -8.9 1.32
|
||||
v 61.8846 -10.903 0
|
||||
v 62.608 -8.6393 1.32
|
||||
v 60.915 -9.9828 0
|
||||
v 61.1854 -9.8708 0
|
||||
v 61.0539 -9.9358 0
|
||||
v 61.3075 -9.7896 0
|
||||
v 61.4178 -9.6928 0
|
||||
v 62.5571 -8.3825 1.32
|
||||
v 59.7354 -8.2175 0
|
||||
v 61.5146 -9.5825 0
|
||||
v 61.5958 -9.4604 0
|
||||
v 59.6542 -8.3396 0
|
||||
v 59.5892 -8.4711 0
|
||||
v 61.6608 -9.3289 0
|
||||
v 59.5422 -8.61 0
|
||||
v 61.7078 -9.19 0
|
||||
v 61.7364 -9.0461 0
|
||||
v 59.5136 -8.7539 0
|
||||
v 61.7464 -8.9 0
|
||||
v 59.5041 -8.9 0
|
||||
v 61.7364 -8.7539 0
|
||||
v 59.5136 -9.0461 0
|
||||
v 61.7078 -8.61 0
|
||||
v 62.4732 -8.1348 1.32
|
||||
v 59.5422 -9.19 0
|
||||
v 61.6608 -8.4711 0
|
||||
v 62.3573 -7.9 1.32
|
||||
v 59.5892 -9.3289 0
|
||||
v 61.5958 -8.3396 0
|
||||
v 61.5146 -8.2175 0
|
||||
v 59.6542 -9.4604 0
|
||||
v 59.7354 -9.5825 0
|
||||
v 62.2124 -7.6822 1.32
|
||||
v 59.8322 -9.6928 0
|
||||
v 61.4178 -8.1072 0
|
||||
v 62.0396 -7.4854 1.32
|
||||
v 61.3075 -8.0104 0
|
||||
v 61.1854 -7.9292 0
|
||||
v 61.8428 -7.3126 1.32
|
||||
v 61.0539 -7.8642 0
|
||||
v 61.625 -7.1677 1.32
|
||||
v 60.915 -7.8172 0
|
||||
v 60.7711 -7.7886 0
|
||||
v 61.3902 -7.0518 1.32
|
||||
v 60.625 -7.7791 0
|
||||
v 60.4789 -7.7886 0
|
||||
v 61.1425 -6.9679 1.32
|
||||
v 60.335 -7.8172 0
|
||||
v 60.8857 -6.917 1.32
|
||||
v 60.625 -6.9 1.32
|
||||
v 60.3643 -6.917 1.32
|
||||
v 60.1075 -6.9679 1.32
|
||||
v 59.8598 -7.0518 1.32
|
||||
v 59.625 -7.1677 1.32
|
||||
v 59.4072 -7.3126 1.32
|
||||
v 62.628 -4.9 1.32
|
||||
v 59.2104 -7.4854 1.32
|
||||
v 59.0376 -7.6822 1.32
|
||||
v 58.8927 -7.9 1.32
|
||||
v 58.7768 -8.1348 1.32
|
||||
v 60.8857 -10.883 1.32
|
||||
v 60.625 -10.901 1.32
|
||||
v 58.6929 -8.3825 1.32
|
||||
v 58.642 -8.6393 1.32
|
||||
v 58.625 -8.9 1.32
|
||||
v 58.642 -9.1607 1.32
|
||||
v 58.6929 -9.4175 1.32
|
||||
v 58.7768 -9.6652 1.32
|
||||
v 58.8927 -9.9 1.32
|
||||
v 59.0376 -10.1178 1.32
|
||||
v 59.2104 -10.3146 1.32
|
||||
v 59.4072 -10.4874 1.32
|
||||
v 59.625 -10.6323 1.32
|
||||
v 59.8598 -10.7482 1.32
|
||||
v 60.1075 -10.8321 1.32
|
||||
v 60.3643 -10.883 1.32
|
||||
v 61.1425 -10.8321 1.32
|
||||
v 61.3902 -10.7482 1.32
|
||||
v 61.625 -10.6323 1.32
|
||||
# 115 vertices
|
||||
|
||||
g group_0_15277357
|
||||
|
||||
usemtl color_15277357
|
||||
s 0
|
||||
|
||||
f 1 2 3
|
||||
f 1 3 4
|
||||
f 4 8 1
|
||||
f 8 10 1
|
||||
f 6 3 5
|
||||
f 37 3 17
|
||||
f 70 3 68
|
||||
f 14 10 8
|
||||
f 14 8 20
|
||||
f 21 22 23
|
||||
f 21 23 25
|
||||
f 112 19 17
|
||||
f 21 25 27
|
||||
f 26 27 25
|
||||
f 19 112 24
|
||||
f 9 2 7
|
||||
f 11 2 9
|
||||
f 32 26 31
|
||||
f 32 27 26
|
||||
f 34 30 32
|
||||
f 30 29 32
|
||||
f 71 23 66
|
||||
f 73 28 71
|
||||
f 23 71 28
|
||||
f 22 55 23
|
||||
f 52 50 34
|
||||
f 33 34 32
|
||||
f 46 22 37
|
||||
f 3 37 22
|
||||
f 34 33 52
|
||||
f 53 52 33
|
||||
f 28 15 2
|
||||
f 6 17 3
|
||||
f 24 37 19
|
||||
f 35 37 24
|
||||
f 39 37 35
|
||||
f 17 19 37
|
||||
f 2 56 3
|
||||
f 21 4 3
|
||||
f 21 3 22
|
||||
f 25 28 1
|
||||
f 53 33 55
|
||||
f 36 55 33
|
||||
f 28 25 23
|
||||
f 42 37 40
|
||||
f 28 2 1
|
||||
f 39 41 37
|
||||
f 55 36 38
|
||||
f 43 37 42
|
||||
f 41 40 37
|
||||
f 45 2 11
|
||||
f 97 35 24
|
||||
f 22 46 47
|
||||
f 49 2 48
|
||||
f 48 2 45
|
||||
f 50 22 47
|
||||
f 51 2 49
|
||||
f 52 22 50
|
||||
f 39 113 41
|
||||
f 53 22 52
|
||||
f 54 2 51
|
||||
f 55 22 53
|
||||
f 114 115 41
|
||||
f 56 2 54
|
||||
f 57 23 55
|
||||
f 37 43 46
|
||||
f 59 23 57
|
||||
f 62 23 59
|
||||
f 64 3 61
|
||||
f 65 23 62
|
||||
f 65 62 63
|
||||
f 66 23 65
|
||||
f 67 3 64
|
||||
f 61 3 58
|
||||
f 69 66 63
|
||||
f 12 3 70
|
||||
f 58 3 56
|
||||
f 5 3 12
|
||||
f 68 3 67
|
||||
f 36 31 38
|
||||
f 101 56 54
|
||||
f 78 28 76
|
||||
f 76 28 74
|
||||
f 101 58 56
|
||||
f 38 31 44
|
||||
f 79 28 78
|
||||
f 81 28 79
|
||||
f 58 102 61
|
||||
f 82 28 81
|
||||
f 73 74 28
|
||||
f 84 28 82
|
||||
f 61 103 64
|
||||
f 15 28 84
|
||||
f 63 60 31
|
||||
f 114 41 113
|
||||
f 7 2 15
|
||||
f 81 79 86
|
||||
f 67 105 68
|
||||
f 87 82 86
|
||||
f 107 70 68
|
||||
f 107 68 106
|
||||
f 40 115 42
|
||||
f 70 107 12
|
||||
f 16 13 42
|
||||
f 43 42 13
|
||||
f 75 72 92
|
||||
f 77 75 92
|
||||
f 18 46 13
|
||||
f 43 13 46
|
||||
f 20 27 32
|
||||
f 27 20 8
|
||||
f 83 80 92
|
||||
f 85 83 92
|
||||
f 18 29 46
|
||||
f 47 46 29
|
||||
f 10 26 1
|
||||
f 25 1 26
|
||||
f 47 29 50
|
||||
f 30 50 29
|
||||
f 92 10 14
|
||||
f 7 15 90
|
||||
f 89 90 15
|
||||
f 30 34 50
|
||||
f 91 9 90
|
||||
f 7 90 9
|
||||
f 89 14 90
|
||||
f 9 91 93
|
||||
f 9 93 11
|
||||
f 90 14 91
|
||||
f 48 45 95
|
||||
f 93 91 14
|
||||
f 38 57 55
|
||||
f 95 94 14
|
||||
f 94 93 14
|
||||
f 94 45 93
|
||||
f 45 11 93
|
||||
f 96 95 14
|
||||
f 44 59 38
|
||||
f 57 38 59
|
||||
f 10 92 26
|
||||
f 31 26 92
|
||||
f 60 62 44
|
||||
f 59 44 62
|
||||
f 89 88 14
|
||||
f 92 14 88
|
||||
f 87 92 88
|
||||
f 87 86 92
|
||||
f 86 85 92
|
||||
f 60 63 62
|
||||
f 24 98 97
|
||||
f 20 32 98
|
||||
f 80 77 92
|
||||
f 69 31 72
|
||||
f 63 31 69
|
||||
f 92 72 31
|
||||
f 60 44 31
|
||||
f 36 33 32
|
||||
f 31 36 32
|
||||
f 39 35 97
|
||||
f 99 96 14
|
||||
f 97 98 32
|
||||
f 98 112 20
|
||||
f 100 99 14
|
||||
f 65 63 66
|
||||
f 94 95 45
|
||||
f 101 100 14
|
||||
f 111 110 20
|
||||
f 20 105 104
|
||||
f 103 102 20
|
||||
f 14 20 101
|
||||
f 104 103 20
|
||||
f 102 101 20
|
||||
f 8 4 27
|
||||
f 4 21 27
|
||||
f 69 72 66
|
||||
f 71 66 72
|
||||
f 96 49 95
|
||||
f 48 95 49
|
||||
f 75 73 72
|
||||
f 71 72 73
|
||||
f 96 99 49
|
||||
f 51 49 99
|
||||
f 77 74 73
|
||||
f 77 73 75
|
||||
f 106 105 20
|
||||
f 99 100 51
|
||||
f 54 51 100
|
||||
f 74 77 76
|
||||
f 80 76 77
|
||||
f 107 106 20
|
||||
f 108 107 20
|
||||
f 83 78 76
|
||||
f 83 76 80
|
||||
f 101 54 100
|
||||
f 109 108 20
|
||||
f 110 109 20
|
||||
f 83 85 78
|
||||
f 79 78 85
|
||||
f 111 20 112
|
||||
f 102 58 101
|
||||
f 85 86 79
|
||||
f 103 61 102
|
||||
f 97 32 113
|
||||
f 81 86 82
|
||||
f 64 103 104
|
||||
f 114 113 32
|
||||
f 82 87 84
|
||||
f 88 84 87
|
||||
f 114 32 115
|
||||
f 104 105 64
|
||||
f 67 64 105
|
||||
f 89 15 88
|
||||
f 84 88 15
|
||||
f 115 32 16
|
||||
f 106 68 105
|
||||
f 16 32 13
|
||||
f 13 32 18
|
||||
f 12 107 108
|
||||
f 29 18 32
|
||||
f 109 5 12
|
||||
f 109 12 108
|
||||
f 5 109 6
|
||||
f 110 6 109
|
||||
f 111 17 6
|
||||
f 111 6 110
|
||||
f 17 111 112
|
||||
f 24 112 98
|
||||
f 113 39 97
|
||||
f 40 41 115
|
||||
f 16 42 115
|
||||
# 230 faces
|
||||
|
||||
#end of obj_0
|
||||
|
64
case/usb-extension.obj
Normal file
@@ -0,0 +1,64 @@
|
||||
# Object Export From Tinkercad Server 2015
|
||||
|
||||
mtllib obj.mtl
|
||||
|
||||
o obj_0
|
||||
v 22.378 -32.248 0
|
||||
v 15.373 -32.248 0
|
||||
v 15.373 -45.253 0
|
||||
v 22.378 -45.253 0
|
||||
v 13.375 -47.25 0
|
||||
v 13.375 -30.25 0
|
||||
v 24.375 -47.25 0
|
||||
v 24.375 -30.25 0
|
||||
v 22.378 -45.253 20
|
||||
v 15.373 -45.253 20
|
||||
v 15.373 -32.248 20
|
||||
v 22.378 -32.248 20
|
||||
v 24.375 -30.25 20
|
||||
v 24.375 -47.25 20
|
||||
v 13.375 -47.25 20
|
||||
v 13.375 -30.25 20
|
||||
# 16 vertices
|
||||
|
||||
g group_0_15277357
|
||||
|
||||
usemtl color_15277357
|
||||
s 0
|
||||
|
||||
f 6 8 2
|
||||
f 4 7 3
|
||||
f 3 5 2
|
||||
f 5 6 2
|
||||
f 5 3 7
|
||||
f 7 4 1
|
||||
f 1 2 8
|
||||
f 7 1 8
|
||||
f 12 13 11
|
||||
f 10 14 9
|
||||
f 8 13 14
|
||||
f 8 14 7
|
||||
f 5 15 16
|
||||
f 5 16 6
|
||||
f 5 14 15
|
||||
f 16 15 11
|
||||
f 10 11 15
|
||||
f 14 10 15
|
||||
f 5 7 14
|
||||
f 16 11 13
|
||||
f 9 14 12
|
||||
f 13 12 14
|
||||
f 9 4 3
|
||||
f 9 3 10
|
||||
f 10 3 2
|
||||
f 10 2 11
|
||||
f 16 13 6
|
||||
f 8 6 13
|
||||
f 12 1 4
|
||||
f 12 4 9
|
||||
f 1 12 11
|
||||
f 1 11 2
|
||||
# 32 faces
|
||||
|
||||
#end of obj_0
|
||||
|
938
supersensor.yaml
139
utemp.yaml
@@ -1,139 +0,0 @@
|
||||
---
|
||||
|
||||
#
|
||||
# utemp is a tiny sensor with a BMP280 and an SGP30 on it that I use for basic temperature/AQ monitoring
|
||||
# in my rack. It's here so I can use it as a package but I don't really expect anyone else to build one.
|
||||
#
|
||||
|
||||
esphome:
|
||||
name: utemp
|
||||
name_add_mac_suffix: true
|
||||
friendly_name: "µtemp Sensor"
|
||||
project:
|
||||
name: "Joshua Boniface.µtemp"
|
||||
version: "1.1"
|
||||
|
||||
dashboard_import:
|
||||
package_import_url: github://joshuaboniface/supersensor/utemp.yaml
|
||||
|
||||
esp8266:
|
||||
board: esp01_1m
|
||||
restore_from_flash: true
|
||||
|
||||
preferences:
|
||||
flash_write_interval: 15sec
|
||||
|
||||
globals:
|
||||
- id: temperature_offset
|
||||
type: float
|
||||
restore_value: true
|
||||
initial_value: "0.0"
|
||||
|
||||
logger:
|
||||
level: INFO
|
||||
baud_rate: 0
|
||||
|
||||
api:
|
||||
reboot_timeout: 15min
|
||||
|
||||
ota:
|
||||
platform: esphome
|
||||
|
||||
web_server:
|
||||
port: 80
|
||||
|
||||
captive_portal:
|
||||
|
||||
mdns:
|
||||
disabled: false
|
||||
|
||||
wifi:
|
||||
ap: {}
|
||||
domain: ""
|
||||
output_power: 8.5dB
|
||||
reboot_timeout: 15min
|
||||
power_save_mode: none
|
||||
|
||||
i2c:
|
||||
- id: i2c_bus
|
||||
sda: GPIO5
|
||||
scl: GPIO4
|
||||
scan: true
|
||||
|
||||
sensor:
|
||||
- platform: sgp30
|
||||
eco2:
|
||||
name: "eCO2"
|
||||
accuracy_decimals: 1
|
||||
tvoc:
|
||||
name: "TVOC"
|
||||
accuracy_decimals: 1
|
||||
store_baseline: yes
|
||||
address: 0x58
|
||||
update_interval: 15s
|
||||
|
||||
- platform: bmp280_i2c
|
||||
temperature:
|
||||
name: "Temperature"
|
||||
oversampling: 16x
|
||||
filters:
|
||||
- offset: !lambda return id(temperature_offset);
|
||||
pressure:
|
||||
name: "Pressure"
|
||||
address: 0x76
|
||||
update_interval: 15s
|
||||
iir_filter: 16x
|
||||
|
||||
- platform: wifi_signal
|
||||
name: "WiFi Signal"
|
||||
update_interval: 60s
|
||||
entity_category: diagnostic
|
||||
|
||||
- platform: uptime
|
||||
name: "Uptime"
|
||||
update_interval: 60s
|
||||
entity_category: diagnostic
|
||||
|
||||
text_sensor:
|
||||
- platform: version
|
||||
name: "ESPHome Version"
|
||||
entity_category: diagnostic
|
||||
|
||||
- platform: wifi_info
|
||||
ip_address:
|
||||
name: "WiFi IP Address"
|
||||
ssid:
|
||||
name: "WiFi SSID"
|
||||
bssid:
|
||||
name: "WiFi BSSID"
|
||||
mac_address:
|
||||
name: "WiFi MAC Address"
|
||||
|
||||
button:
|
||||
- platform: restart
|
||||
name: "ESP8266 Restart"
|
||||
icon: mdi:power-cycle
|
||||
entity_category: diagnostic
|
||||
|
||||
- platform: factory_reset
|
||||
name: "ESP8266 Factory Reset"
|
||||
icon: mdi:restart-alert
|
||||
entity_category: diagnostic
|
||||
|
||||
number:
|
||||
# Temperature offset:
|
||||
# A calibration from -10 to +6 for the temperature sensor of the BMP280
|
||||
- platform: template
|
||||
name: "Temperature Offset"
|
||||
id: temperature_offset_setter
|
||||
min_value: -10
|
||||
max_value: 6
|
||||
step: 0.1
|
||||
lambda: |-
|
||||
return id(temperature_offset);
|
||||
set_action:
|
||||
then:
|
||||
- globals.set:
|
||||
id: temperature_offset
|
||||
value: !lambda 'return float(x);'
|
||||
|