mirror of
https://github.com/esphome/esphome.git
synced 2025-11-02 08:01:50 +00:00
Compare commits
146 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a3b2d384f5 | ||
|
|
50238f8d72 | ||
|
|
704470d606 | ||
|
|
f7e6195466 | ||
|
|
a0bb7c3ed0 | ||
|
|
c4edd3047f | ||
|
|
c50da1593a | ||
|
|
1d06426281 | ||
|
|
9c5b693dd5 | ||
|
|
5fecc70db1 | ||
|
|
1a04e2d1b8 | ||
|
|
52c4dd0e35 | ||
|
|
ff90f6a440 | ||
|
|
839fe49e61 | ||
|
|
ff050d634a | ||
|
|
228670df78 | ||
|
|
cfe4638665 | ||
|
|
b7352b1345 | ||
|
|
32ae8fc2d0 | ||
|
|
86df4c1d8d | ||
|
|
dc4a88029c | ||
|
|
5da9b2ede7 | ||
|
|
29cfcfaf0f | ||
|
|
61bfd347ea | ||
|
|
b7436c0b22 | ||
|
|
8a45dfac5c | ||
|
|
51ab0f0b78 | ||
|
|
bf0cce4ad8 | ||
|
|
60e6366521 | ||
|
|
072b2c445c | ||
|
|
219fe41831 | ||
|
|
dcc8bb83af | ||
|
|
a8e3521f3c | ||
|
|
706dc6d116 | ||
|
|
84accb6df6 | ||
|
|
8421570b18 | ||
|
|
d355543ac9 | ||
|
|
3a597c5aa6 | ||
|
|
c7dddaded4 | ||
|
|
aae4b2ea5d | ||
|
|
310e2a0b20 | ||
|
|
0b04d143ac | ||
|
|
53c231a7eb | ||
|
|
d44ce82aa1 | ||
|
|
a055de48e4 | ||
|
|
37b8d665fe | ||
|
|
dd7c8dabb1 | ||
|
|
e41a9875e3 | ||
|
|
c5c42c4338 | ||
|
|
531428b8b0 | ||
|
|
ea8068e001 | ||
|
|
7842a55c81 | ||
|
|
51d39862b1 | ||
|
|
bfea6ca79b | ||
|
|
6297395018 | ||
|
|
a5b49dbfa6 | ||
|
|
7c0d777173 | ||
|
|
74878276fc | ||
|
|
226e3b1dad | ||
|
|
7752794fc5 | ||
|
|
b3094d6a53 | ||
|
|
e3640e710f | ||
|
|
2ef64b55c5 | ||
|
|
7f6672bb37 | ||
|
|
68a3b31628 | ||
|
|
1b35855e68 | ||
|
|
1e1837000d | ||
|
|
e2d5257632 | ||
|
|
387c75793b | ||
|
|
4f3a74d08a | ||
|
|
fdbc59a159 | ||
|
|
0db37bb55c | ||
|
|
2ff2750628 | ||
|
|
eae5c17b87 | ||
|
|
a59cde91ad | ||
|
|
1f243ae37e | ||
|
|
603f82977e | ||
|
|
2d70422a6f | ||
|
|
e2c8b21195 | ||
|
|
7adaeacd0b | ||
|
|
3aaa92fdff | ||
|
|
5efd076c08 | ||
|
|
1ca241615d | ||
|
|
b8aa84002a | ||
|
|
10cc0b1d5b | ||
|
|
11d9c203c1 | ||
|
|
c9ab454c3c | ||
|
|
4a55692885 | ||
|
|
88c129e705 | ||
|
|
80b48f01fb | ||
|
|
642bc91a76 | ||
|
|
d69926ee56 | ||
|
|
4758403d44 | ||
|
|
4b0ec5c28a | ||
|
|
4b2a9e5e49 | ||
|
|
1449c51d49 | ||
|
|
a451705e0b | ||
|
|
2e6db39173 | ||
|
|
373f75253c | ||
|
|
724842084e | ||
|
|
8f3635b167 | ||
|
|
11605a36f7 | ||
|
|
533f81d625 | ||
|
|
aacb9e44e8 | ||
|
|
c6e3f1bca6 | ||
|
|
a933d4aeb6 | ||
|
|
caa5b20791 | ||
|
|
e2ad9ed746 | ||
|
|
32c0e7c2ae | ||
|
|
6c564c7b7f | ||
|
|
c81e3a3be4 | ||
|
|
6b1b9ef7ec | ||
|
|
c26a8b8718 | ||
|
|
4a89a475bd | ||
|
|
8cf15c7f5c | ||
|
|
adc76ca1b8 | ||
|
|
8f8892440c | ||
|
|
570843150d | ||
|
|
f3fc9e4142 | ||
|
|
075fcb77a8 | ||
|
|
e5899ff717 | ||
|
|
2fb3970027 | ||
|
|
1a4efa1b8c | ||
|
|
72f656ffef | ||
|
|
b60239d5e5 | ||
|
|
d02e280c3c | ||
|
|
6535b0966e | ||
|
|
82dbacbee5 | ||
|
|
2432901974 | ||
|
|
ebb5d58c14 | ||
|
|
605e365405 | ||
|
|
5ab995d8ca | ||
|
|
4248741b11 | ||
|
|
4b8ecc7634 | ||
|
|
25d04c759c | ||
|
|
b4ec84030e | ||
|
|
29e8761373 | ||
|
|
a04299c59e | ||
|
|
d7bf3c51d9 | ||
|
|
ac0b095941 | ||
|
|
cda9bad233 | ||
|
|
41db8a1264 | ||
|
|
e7e785fd60 | ||
|
|
300d3a1f46 | ||
|
|
356554c08d | ||
|
|
ced28ad006 |
2
.github/workflows/ci-docker.yml
vendored
2
.github/workflows/ci-docker.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up env variables
|
||||
run: |
|
||||
base_version="2.4.1"
|
||||
base_version="2.6.0"
|
||||
|
||||
if [[ "${{ matrix.build_type }}" == "hassio" ]]; then
|
||||
build_from="esphome/esphome-hassio-base-${{ matrix.arch }}:${base_version}"
|
||||
|
||||
2
.github/workflows/release-dev.yml
vendored
2
.github/workflows/release-dev.yml
vendored
@@ -190,7 +190,7 @@ jobs:
|
||||
echo "::set-env name=TAG::${TAG}"
|
||||
- name: Set up env variables
|
||||
run: |
|
||||
base_version="2.4.1"
|
||||
base_version="2.6.0"
|
||||
|
||||
if [[ "${{ matrix.build_type }}" == "hassio" ]]; then
|
||||
build_from="esphome/esphome-hassio-base-${{ matrix.arch }}:${base_version}"
|
||||
|
||||
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@@ -210,7 +210,7 @@ jobs:
|
||||
echo "::set-env name=TAG::${TAG}"
|
||||
- name: Set up env variables
|
||||
run: |
|
||||
base_version="2.4.1"
|
||||
base_version="2.6.0"
|
||||
|
||||
if [[ "${{ matrix.build_type }}" == "hassio" ]]; then
|
||||
build_from="esphome/esphome-hassio-base-${{ matrix.arch }}:${base_version}"
|
||||
@@ -226,7 +226,7 @@ jobs:
|
||||
cache_tag="beta"
|
||||
else
|
||||
cache_tag="latest"
|
||||
end
|
||||
fi
|
||||
|
||||
# Set env variables so these values don't need to be calculated again
|
||||
echo "::set-env name=BUILD_FROM::${build_from}"
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -119,3 +119,4 @@ config/
|
||||
tests/build/
|
||||
tests/.esphome/
|
||||
/.temp-clang-tidy.cpp
|
||||
/.idea/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
ARG BUILD_FROM=esphome/esphome-base-amd64:2.4.1
|
||||
ARG BUILD_FROM=esphome/esphome-base-amd64:2.6.0
|
||||
FROM ${BUILD_FROM}
|
||||
|
||||
# First install requirements to leverage caching when requirements don't change
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM esphome/esphome-base-amd64:2.4.1
|
||||
FROM esphome/esphome-base-amd64:2.6.0
|
||||
|
||||
COPY . .
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM esphome/esphome-lint-base:2.4.1
|
||||
FROM esphome/esphome-lint-base:2.6.0
|
||||
|
||||
COPY requirements.txt requirements_test.txt /
|
||||
RUN pip3 install --no-cache-dir -r /requirements.txt -r /requirements_test.txt
|
||||
|
||||
@@ -3,7 +3,8 @@ import esphome.config_validation as cv
|
||||
from esphome import automation
|
||||
from esphome.automation import Condition
|
||||
from esphome.const import CONF_DATA, CONF_DATA_TEMPLATE, CONF_ID, CONF_PASSWORD, CONF_PORT, \
|
||||
CONF_REBOOT_TIMEOUT, CONF_SERVICE, CONF_VARIABLES, CONF_SERVICES, CONF_TRIGGER_ID, CONF_EVENT
|
||||
CONF_REBOOT_TIMEOUT, CONF_SERVICE, CONF_VARIABLES, CONF_SERVICES, CONF_TRIGGER_ID, CONF_EVENT, \
|
||||
CONF_TAG
|
||||
from esphome.core import coroutine_with_priority
|
||||
|
||||
DEPENDENCIES = ['network']
|
||||
@@ -137,6 +138,23 @@ def homeassistant_event_to_code(config, action_id, template_arg, args):
|
||||
yield var
|
||||
|
||||
|
||||
HOMEASSISTANT_TAG_SCANNED_ACTION_SCHEMA = cv.maybe_simple_value({
|
||||
cv.GenerateID(): cv.use_id(APIServer),
|
||||
cv.Required(CONF_TAG): cv.templatable(cv.string_strict),
|
||||
}, key=CONF_TAG)
|
||||
|
||||
|
||||
@automation.register_action('homeassistant.tag_scanned', HomeAssistantServiceCallAction,
|
||||
HOMEASSISTANT_TAG_SCANNED_ACTION_SCHEMA)
|
||||
def homeassistant_tag_scanned_to_code(config, action_id, template_arg, args):
|
||||
serv = yield cg.get_variable(config[CONF_ID])
|
||||
var = cg.new_Pvariable(action_id, template_arg, serv, True)
|
||||
cg.add(var.set_service('esphome.tag_scanned'))
|
||||
templ = yield cg.templatable(config[CONF_TAG], args, cg.std_string)
|
||||
cg.add(var.add_data('tag_id', templ))
|
||||
yield var
|
||||
|
||||
|
||||
@automation.register_condition('api.connected', APIConnectedCondition, {})
|
||||
def api_connected_to_code(config, condition_id, template_arg, args):
|
||||
yield cg.new_Pvariable(condition_id, template_arg)
|
||||
|
||||
@@ -12,4 +12,4 @@ def to_code(config):
|
||||
cg.add_library('AsyncTCP-esphome', '1.1.1')
|
||||
elif CORE.is_esp8266:
|
||||
# https://github.com/OttoWinter/ESPAsyncTCP
|
||||
cg.add_library('ESPAsyncTCP-esphome', '1.2.2')
|
||||
cg.add_library('ESPAsyncTCP-esphome', '1.2.3')
|
||||
|
||||
@@ -204,31 +204,33 @@ void DisplayBuffer::vprintf_(int x, int y, Font *font, Color color, TextAlign al
|
||||
if (ret > 0)
|
||||
this->print(x, y, font, color, align, buffer);
|
||||
}
|
||||
void DisplayBuffer::image(int x, int y, Image *image) { this->image(x, y, COLOR_ON, image); }
|
||||
void DisplayBuffer::image(int x, int y, Color color, Image *image, bool invert) {
|
||||
if (image->get_type() == BINARY) {
|
||||
for (int img_x = 0; img_x < image->get_width(); img_x++) {
|
||||
for (int img_y = 0; img_y < image->get_height(); img_y++) {
|
||||
if (invert)
|
||||
this->draw_pixel_at(x + img_x, y + img_y, image->get_pixel(img_x, img_y) ? COLOR_OFF : color);
|
||||
else
|
||||
this->draw_pixel_at(x + img_x, y + img_y, image->get_pixel(img_x, img_y) ? color : COLOR_OFF);
|
||||
|
||||
void DisplayBuffer::image(int x, int y, Image *image, Color color_on, Color color_off) {
|
||||
switch (image->get_type()) {
|
||||
case IMAGE_TYPE_BINARY:
|
||||
for (int img_x = 0; img_x < image->get_width(); img_x++) {
|
||||
for (int img_y = 0; img_y < image->get_height(); img_y++) {
|
||||
this->draw_pixel_at(x + img_x, y + img_y, image->get_pixel(img_x, img_y) ? color_on : color_off);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (image->get_type() == GRAYSCALE) {
|
||||
for (int img_x = 0; img_x < image->get_width(); img_x++) {
|
||||
for (int img_y = 0; img_y < image->get_height(); img_y++) {
|
||||
this->draw_pixel_at(x + img_x, y + img_y, image->get_grayscale_pixel(img_x, img_y));
|
||||
break;
|
||||
case IMAGE_TYPE_GRAYSCALE:
|
||||
for (int img_x = 0; img_x < image->get_width(); img_x++) {
|
||||
for (int img_y = 0; img_y < image->get_height(); img_y++) {
|
||||
this->draw_pixel_at(x + img_x, y + img_y, image->get_grayscale_pixel(img_x, img_y));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (image->get_type() == RGB) {
|
||||
for (int img_x = 0; img_x < image->get_width(); img_x++) {
|
||||
for (int img_y = 0; img_y < image->get_height(); img_y++) {
|
||||
this->draw_pixel_at(x + img_x, y + img_y, image->get_color_pixel(img_x, img_y));
|
||||
break;
|
||||
case IMAGE_TYPE_RGB24:
|
||||
for (int img_x = 0; img_x < image->get_width(); img_x++) {
|
||||
for (int img_y = 0; img_y < image->get_height(); img_y++) {
|
||||
this->draw_pixel_at(x + img_x, y + img_y, image->get_color_pixel(img_x, img_y));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayBuffer::get_text_bounds(int x, int y, const char *text, Font *font, TextAlign align, int *x1, int *y1,
|
||||
int *width, int *height) {
|
||||
int x_offset, baseline;
|
||||
@@ -463,15 +465,14 @@ Color Image::get_grayscale_pixel(int x, int y) const {
|
||||
if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
|
||||
return 0;
|
||||
const uint32_t pos = (x + y * this->width_);
|
||||
return Color(pgm_read_byte(this->data_start_ + pos) << 24);
|
||||
const uint8_t gray = pgm_read_byte(this->data_start_ + pos);
|
||||
return Color(gray | gray << 8 | gray << 16 | gray << 24);
|
||||
}
|
||||
int Image::get_width() const { return this->width_; }
|
||||
int Image::get_height() const { return this->height_; }
|
||||
ImageType Image::get_type() const { return this->type_; }
|
||||
Image::Image(const uint8_t *data_start, int width, int height)
|
||||
: width_(width), height_(height), data_start_(data_start) {}
|
||||
Image::Image(const uint8_t *data_start, int width, int height, int type)
|
||||
: width_(width), height_(height), type_((ImageType) type), data_start_(data_start) {}
|
||||
Image::Image(const uint8_t *data_start, int width, int height, ImageType type)
|
||||
: width_(width), height_(height), type_(type), data_start_(data_start) {}
|
||||
|
||||
DisplayPage::DisplayPage(const display_writer_t &writer) : writer_(writer) {}
|
||||
void DisplayPage::show() { this->parent_->show_page(this); }
|
||||
|
||||
@@ -68,7 +68,7 @@ extern const Color COLOR_OFF;
|
||||
/// Turn the pixel ON.
|
||||
extern const Color COLOR_ON;
|
||||
|
||||
enum ImageType { BINARY = 0, GRAYSCALE = 1, RGB = 2 };
|
||||
enum ImageType { IMAGE_TYPE_BINARY = 0, IMAGE_TYPE_GRAYSCALE = 1, IMAGE_TYPE_RGB24 = 2 };
|
||||
|
||||
enum DisplayRotation {
|
||||
DISPLAY_ROTATION_0_DEGREES = 0,
|
||||
@@ -262,9 +262,15 @@ class DisplayBuffer {
|
||||
__attribute__((format(strftime, 5, 0)));
|
||||
#endif
|
||||
|
||||
/// Draw the `image` with the top-left corner at [x,y] to the screen.
|
||||
void image(int x, int y, Image *image);
|
||||
void image(int x, int y, Color color, Image *image, bool invert = false);
|
||||
/** Draw the `image` with the top-left corner at [x,y] to the screen.
|
||||
*
|
||||
* @param x The x coordinate of the upper left corner.
|
||||
* @param y The y coordinate of the upper left corner.
|
||||
* @param image The image to draw
|
||||
* @param color_on The color to replace in binary images for the on bits.
|
||||
* @param color_off The color to replace in binary images for the off bits.
|
||||
*/
|
||||
void image(int x, int y, Image *image, Color color_on = COLOR_ON, Color color_off = COLOR_OFF);
|
||||
|
||||
/** Get the text bounds of the given string.
|
||||
*
|
||||
@@ -381,8 +387,7 @@ class Font {
|
||||
|
||||
class Image {
|
||||
public:
|
||||
Image(const uint8_t *data_start, int width, int height);
|
||||
Image(const uint8_t *data_start, int width, int height, int type);
|
||||
Image(const uint8_t *data_start, int width, int height, ImageType type);
|
||||
bool get_pixel(int x, int y) const;
|
||||
Color get_color_pixel(int x, int y) const;
|
||||
Color get_grayscale_pixel(int x, int y) const;
|
||||
@@ -393,7 +398,7 @@ class Image {
|
||||
protected:
|
||||
int width_;
|
||||
int height_;
|
||||
ImageType type_{BINARY};
|
||||
ImageType type_;
|
||||
const uint8_t *data_start_;
|
||||
};
|
||||
|
||||
|
||||
@@ -4,14 +4,20 @@ from esphome import core
|
||||
from esphome.components import display, font
|
||||
import esphome.config_validation as cv
|
||||
import esphome.codegen as cg
|
||||
from esphome.const import CONF_FILE, CONF_ID, CONF_RESIZE, CONF_TYPE
|
||||
from esphome.const import CONF_FILE, CONF_ID, CONF_TYPE, CONF_RESIZE
|
||||
from esphome.core import CORE, HexInt
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ['display']
|
||||
MULTI_CONF = True
|
||||
|
||||
ImageType = {'binary': 0, 'grayscale': 1, 'rgb': 2}
|
||||
|
||||
ImageType = display.display_ns.enum('ImageType')
|
||||
IMAGE_TYPE = {
|
||||
'BINARY': ImageType.IMAGE_TYPE_BINARY,
|
||||
'GRAYSCALE': ImageType.IMAGE_TYPE_GRAYSCALE,
|
||||
'RGB24': ImageType.IMAGE_TYPE_RGB24,
|
||||
}
|
||||
|
||||
Image_ = display.display_ns.class_('Image')
|
||||
|
||||
@@ -21,7 +27,7 @@ IMAGE_SCHEMA = cv.Schema({
|
||||
cv.Required(CONF_ID): cv.declare_id(Image_),
|
||||
cv.Required(CONF_FILE): cv.file_,
|
||||
cv.Optional(CONF_RESIZE): cv.dimensions,
|
||||
cv.Optional(CONF_TYPE): cv.string,
|
||||
cv.Optional(CONF_TYPE, default='BINARY'): cv.enum(IMAGE_TYPE, upper=True),
|
||||
cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8),
|
||||
})
|
||||
|
||||
@@ -37,44 +43,40 @@ def to_code(config):
|
||||
except Exception as e:
|
||||
raise core.EsphomeError(f"Could not load image file {path}: {e}")
|
||||
|
||||
width, height = image.size
|
||||
|
||||
if CONF_RESIZE in config:
|
||||
image.thumbnail(config[CONF_RESIZE])
|
||||
|
||||
if CONF_TYPE in config:
|
||||
if config[CONF_TYPE].startswith('GRAYSCALE'):
|
||||
width, height = image.size
|
||||
image = image.convert('L', dither=Image.NONE)
|
||||
pixels = list(image.getdata())
|
||||
data = [0 for _ in range(height * width)]
|
||||
pos = 0
|
||||
for pix in pixels:
|
||||
data[pos] = pix
|
||||
pos += 1
|
||||
rhs = [HexInt(x) for x in data]
|
||||
prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
|
||||
cg.new_Pvariable(config[CONF_ID], prog_arr, width, height, ImageType['grayscale'])
|
||||
elif config[CONF_TYPE].startswith('RGB'):
|
||||
width, height = image.size
|
||||
image = image.convert('RGB')
|
||||
pixels = list(image.getdata())
|
||||
data = [0 for _ in range(height * width * 3)]
|
||||
pos = 0
|
||||
for pix in pixels:
|
||||
data[pos] = pix[0]
|
||||
pos += 1
|
||||
data[pos] = pix[1]
|
||||
pos += 1
|
||||
data[pos] = pix[2]
|
||||
pos += 1
|
||||
rhs = [HexInt(x) for x in data]
|
||||
prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
|
||||
cg.new_Pvariable(config[CONF_ID], prog_arr, width, height, ImageType['rgb'])
|
||||
else:
|
||||
image = image.convert('1', dither=Image.NONE)
|
||||
width, height = image.size
|
||||
else:
|
||||
if width > 500 or height > 500:
|
||||
_LOGGER.warning("The image you requested is very big. Please consider using"
|
||||
" the resize parameter.")
|
||||
|
||||
if config[CONF_TYPE] == 'GRAYSCALE':
|
||||
image = image.convert('L', dither=Image.NONE)
|
||||
pixels = list(image.getdata())
|
||||
data = [0 for _ in range(height * width)]
|
||||
pos = 0
|
||||
for pix in pixels:
|
||||
data[pos] = pix
|
||||
pos += 1
|
||||
|
||||
elif config[CONF_TYPE] == 'RGB24':
|
||||
image = image.convert('RGB')
|
||||
pixels = list(image.getdata())
|
||||
data = [0 for _ in range(height * width * 3)]
|
||||
pos = 0
|
||||
for pix in pixels:
|
||||
data[pos] = pix[0]
|
||||
pos += 1
|
||||
data[pos] = pix[1]
|
||||
pos += 1
|
||||
data[pos] = pix[2]
|
||||
pos += 1
|
||||
|
||||
elif config[CONF_TYPE] == 'BINARY':
|
||||
image = image.convert('1', dither=Image.NONE)
|
||||
width8 = ((width + 7) // 8) * 8
|
||||
data = [0 for _ in range(height * width8 // 8)]
|
||||
for y in range(height):
|
||||
@@ -84,6 +86,7 @@ def to_code(config):
|
||||
pos = x + y * width8
|
||||
data[pos // 8] |= 0x80 >> (pos % 8)
|
||||
|
||||
rhs = [HexInt(x) for x in data]
|
||||
prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
|
||||
cg.new_Pvariable(config[CONF_ID], prog_arr, width, height)
|
||||
rhs = [HexInt(x) for x in data]
|
||||
prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
|
||||
cg.new_Pvariable(config[CONF_ID], prog_arr, width, height,
|
||||
IMAGE_TYPE[config[CONF_TYPE]])
|
||||
|
||||
@@ -11,6 +11,7 @@ static const char *TAG = "remote_receiver.esp32";
|
||||
|
||||
void RemoteReceiverComponent::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up Remote Receiver...");
|
||||
this->pin_->setup();
|
||||
rmt_config_t rmt{};
|
||||
this->config_rmt(rmt);
|
||||
rmt.gpio_num = gpio_num_t(this->pin_->get_pin());
|
||||
|
||||
@@ -50,7 +50,7 @@ bool parse_ruuvi_data_byte(const esp32_ble_tracker::adv_data_t &adv_data, RuuviP
|
||||
const float acceleration_y = (int16_t(data[8] << 8) + int16_t(data[9])) / 1000.0f;
|
||||
const float acceleration_z = (int16_t(data[10] << 8) + int16_t(data[11])) / 1000.0f;
|
||||
|
||||
const uint8_t power_info = (data[12] << 8) | data[13];
|
||||
const uint16_t power_info = (uint16_t(data[12] << 8) | data[13]);
|
||||
const float battery_voltage = ((power_info >> 5) + 1600.0f) / 1000.0f;
|
||||
const float tx_power = ((power_info & 0x1F) * 2.0f) - 40.0f;
|
||||
|
||||
|
||||
@@ -18,14 +18,14 @@ ParallelScript = script_ns.class_('ParallelScript', Script)
|
||||
|
||||
CONF_SINGLE = 'single'
|
||||
CONF_RESTART = 'restart'
|
||||
CONF_QUEUE = 'queue'
|
||||
CONF_QUEUED = 'queued'
|
||||
CONF_PARALLEL = 'parallel'
|
||||
CONF_MAX_RUNS = 'max_runs'
|
||||
|
||||
SCRIPT_MODES = {
|
||||
CONF_SINGLE: SingleScript,
|
||||
CONF_RESTART: RestartScript,
|
||||
CONF_QUEUE: QueueingScript,
|
||||
CONF_QUEUED: QueueingScript,
|
||||
CONF_PARALLEL: ParallelScript,
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ SCRIPT_MODES = {
|
||||
def check_max_runs(value):
|
||||
if CONF_MAX_RUNS not in value:
|
||||
return value
|
||||
if value[CONF_MODE] not in [CONF_QUEUE, CONF_PARALLEL]:
|
||||
if value[CONF_MODE] not in [CONF_QUEUED, CONF_PARALLEL]:
|
||||
raise cv.Invalid("The option 'max_runs' is only valid in 'queue' and 'parallel' mode.",
|
||||
path=[CONF_MAX_RUNS])
|
||||
return value
|
||||
@@ -65,7 +65,7 @@ def to_code(config):
|
||||
if CONF_MAX_RUNS in conf:
|
||||
cg.add(trigger.set_max_runs(conf[CONF_MAX_RUNS]))
|
||||
|
||||
if conf[CONF_MODE] == CONF_QUEUE:
|
||||
if conf[CONF_MODE] == CONF_QUEUED:
|
||||
yield cg.register_component(trigger, conf)
|
||||
|
||||
triggers.append((trigger, conf))
|
||||
|
||||
@@ -33,7 +33,7 @@ void QueueingScript::execute() {
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Script '%s' queueing new instance (mode: queue)", this->name_.c_str());
|
||||
ESP_LOGD(TAG, "Script '%s' queueing new instance (mode: queued)", this->name_.c_str());
|
||||
this->num_runs_++;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -33,10 +33,6 @@ void SNTPComponent::setup() {
|
||||
sntp_setservername(2, strdup(this->server_3_.c_str()));
|
||||
}
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
// let localtime/gmtime handle timezones, not sntp
|
||||
sntp_set_timezone(0);
|
||||
#endif
|
||||
sntp_init();
|
||||
}
|
||||
void SNTPComponent::dump_config() {
|
||||
|
||||
@@ -41,7 +41,7 @@ def setup_ssd1036(var, config):
|
||||
reset = yield cg.gpio_pin_expression(config[CONF_RESET_PIN])
|
||||
cg.add(var.set_reset_pin(reset))
|
||||
if CONF_BRIGHTNESS in config:
|
||||
cg.add(var.set_brightness(config[CONF_BRIGHTNESS]))
|
||||
cg.add(var.init_brightness(config[CONF_BRIGHTNESS]))
|
||||
if CONF_EXTERNAL_VCC in config:
|
||||
cg.add(var.set_external_vcc(config[CONF_EXTERNAL_VCC]))
|
||||
if CONF_LAMBDA in config:
|
||||
|
||||
@@ -5,7 +5,11 @@
|
||||
namespace esphome {
|
||||
namespace ssd1306_base {
|
||||
|
||||
static const char *TAG = "sd1306";
|
||||
static const char *TAG = "ssd1306";
|
||||
|
||||
static const uint8_t BLACK = 0;
|
||||
static const uint8_t WHITE = 1;
|
||||
static const uint8_t SSD1306_MAX_CONTRAST = 255;
|
||||
|
||||
static const uint8_t SSD1306_COMMAND_DISPLAY_OFF = 0xAE;
|
||||
static const uint8_t SSD1306_COMMAND_DISPLAY_ON = 0xAF;
|
||||
@@ -69,27 +73,6 @@ void SSD1306::setup() {
|
||||
break;
|
||||
}
|
||||
|
||||
this->command(SSD1306_COMMAND_SET_CONTRAST);
|
||||
switch (this->model_) {
|
||||
case SSD1306_MODEL_128_32:
|
||||
case SH1106_MODEL_128_32:
|
||||
this->command(0x8F);
|
||||
break;
|
||||
case SSD1306_MODEL_128_64:
|
||||
case SH1106_MODEL_128_64:
|
||||
case SSD1306_MODEL_64_48:
|
||||
case SH1106_MODEL_64_48:
|
||||
this->command(int(255 * (this->brightness_)));
|
||||
break;
|
||||
case SSD1306_MODEL_96_16:
|
||||
case SH1106_MODEL_96_16:
|
||||
if (this->external_vcc_)
|
||||
this->command(0x10);
|
||||
else
|
||||
this->command(0xAF);
|
||||
break;
|
||||
}
|
||||
|
||||
this->command(SSD1306_COMMAND_SET_PRE_CHARGE);
|
||||
if (this->external_vcc_)
|
||||
this->command(0x22);
|
||||
@@ -104,7 +87,12 @@ void SSD1306::setup() {
|
||||
|
||||
this->command(SSD1306_COMMAND_DEACTIVATE_SCROLL);
|
||||
|
||||
this->command(SSD1306_COMMAND_DISPLAY_ON);
|
||||
set_brightness(this->brightness_);
|
||||
|
||||
this->fill(BLACK); // clear display - ensures we do not see garbage at power-on
|
||||
this->display(); // ...write buffer, which actually clears the display's memory
|
||||
|
||||
this->turn_on();
|
||||
}
|
||||
void SSD1306::display() {
|
||||
if (this->is_sh1106_()) {
|
||||
@@ -140,6 +128,22 @@ void SSD1306::update() {
|
||||
this->do_update_();
|
||||
this->display();
|
||||
}
|
||||
void SSD1306::set_brightness(float brightness) {
|
||||
// validation
|
||||
this->brightness_ = clamp(brightness, 0, 1);
|
||||
// now write the new brightness level to the display
|
||||
this->command(SSD1306_COMMAND_SET_CONTRAST);
|
||||
this->command(int(SSD1306_MAX_CONTRAST * (this->brightness_)));
|
||||
}
|
||||
bool SSD1306::is_on() { return this->is_on_; }
|
||||
void SSD1306::turn_on() {
|
||||
this->command(SSD1306_COMMAND_DISPLAY_ON);
|
||||
this->is_on_ = true;
|
||||
}
|
||||
void SSD1306::turn_off() {
|
||||
this->command(SSD1306_COMMAND_DISPLAY_OFF);
|
||||
this->is_on_ = false;
|
||||
}
|
||||
int SSD1306::get_height_internal() {
|
||||
switch (this->model_) {
|
||||
case SSD1306_MODEL_128_32:
|
||||
@@ -178,7 +182,6 @@ int SSD1306::get_width_internal() {
|
||||
size_t SSD1306::get_buffer_length_() {
|
||||
return size_t(this->get_width_internal()) * size_t(this->get_height_internal()) / 8u;
|
||||
}
|
||||
|
||||
void HOT SSD1306::draw_absolute_pixel_internal(int x, int y, Color color) {
|
||||
if (x >= this->get_width_internal() || x < 0 || y >= this->get_height_internal() || y < 0)
|
||||
return;
|
||||
|
||||
@@ -29,8 +29,11 @@ class SSD1306 : public PollingComponent, public display::DisplayBuffer {
|
||||
void set_model(SSD1306Model model) { this->model_ = model; }
|
||||
void set_reset_pin(GPIOPin *reset_pin) { this->reset_pin_ = reset_pin; }
|
||||
void set_external_vcc(bool external_vcc) { this->external_vcc_ = external_vcc; }
|
||||
void set_brightness(float brightness) { this->brightness_ = brightness; }
|
||||
|
||||
void init_brightness(float brightness) { this->brightness_ = brightness; }
|
||||
void set_brightness(float brightness);
|
||||
bool is_on();
|
||||
void turn_on();
|
||||
void turn_off();
|
||||
float get_setup_priority() const override { return setup_priority::PROCESSOR; }
|
||||
void fill(Color color) override;
|
||||
|
||||
@@ -51,6 +54,7 @@ class SSD1306 : public PollingComponent, public display::DisplayBuffer {
|
||||
SSD1306Model model_{SSD1306_MODEL_128_64};
|
||||
GPIOPin *reset_pin_{nullptr};
|
||||
bool external_vcc_{false};
|
||||
bool is_on_{false};
|
||||
float brightness_{1.0};
|
||||
};
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ def to_code(config):
|
||||
cg.add(var.set_optimistic(config[CONF_OPTIMISTIC]))
|
||||
cg.add(var.set_assumed_state(config[CONF_ASSUMED_STATE]))
|
||||
cg.add(var.set_restore_mode(config[CONF_RESTORE_MODE]))
|
||||
cg.add(var.set_has_position(config[CONF_HAS_POSITION]))
|
||||
|
||||
|
||||
@automation.register_action('cover.template.publish', cover.CoverPublishAction, cv.Schema({
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
#include "sys/time.h"
|
||||
#endif
|
||||
#include "errno.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace time {
|
||||
@@ -20,8 +21,18 @@ void RealTimeClock::synchronize_epoch_(uint32_t epoch) {
|
||||
struct timeval timev {
|
||||
.tv_sec = static_cast<time_t>(epoch), .tv_usec = 0,
|
||||
};
|
||||
ESP_LOGVV(TAG, "Got epoch %u", epoch);
|
||||
timezone tz = {0, 0};
|
||||
settimeofday(&timev, &tz);
|
||||
int ret = settimeofday(&timev, &tz);
|
||||
if (ret == EINVAL) {
|
||||
// Some ESP8266 frameworks abort when timezone parameter is not NULL
|
||||
// while ESP32 expects it not to be NULL
|
||||
ret = settimeofday(&timev, nullptr);
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
ESP_LOGW(TAG, "setimeofday() failed with code %d", ret);
|
||||
}
|
||||
|
||||
auto time = this->now();
|
||||
char buf[128];
|
||||
|
||||
@@ -232,7 +232,7 @@ uint8_t TM1637Display::print(uint8_t start_pos, const char* str) {
|
||||
uint8_t pos = start_pos;
|
||||
for (; *str != '\0'; str++) {
|
||||
uint8_t data = TM1637_UNKNOWN_CHAR;
|
||||
if (*str >= ' ' && *str <= '}')
|
||||
if (*str >= ' ' && *str <= '~')
|
||||
data = pgm_read_byte(&TM1637_ASCII_TO_RAW[*str - ' ']);
|
||||
|
||||
if (data == TM1637_UNKNOWN_CHAR) {
|
||||
|
||||
@@ -7,9 +7,9 @@ from .. import tuya_ns, CONF_TUYA_ID, Tuya
|
||||
DEPENDENCIES = ['tuya']
|
||||
CODEOWNERS = ['@jesserockz']
|
||||
|
||||
CONF_TARGET_TEMPERATURE_DATAPOINT = "target_temperature_datapoint"
|
||||
CONF_CURRENT_TEMPERATURE_DATAPOINT = "current_temperature_datapoint"
|
||||
# CONF_ECO_MODE_DATAPOINT = "eco_mode_datapoint"
|
||||
CONF_TARGET_TEMPERATURE_DATAPOINT = 'target_temperature_datapoint'
|
||||
CONF_CURRENT_TEMPERATURE_DATAPOINT = 'current_temperature_datapoint'
|
||||
CONF_TEMPERATURE_MULTIPLIER = 'temperature_multiplier'
|
||||
|
||||
TuyaClimate = tuya_ns.class_('TuyaClimate', climate.Climate, cg.Component)
|
||||
|
||||
@@ -19,7 +19,7 @@ CONFIG_SCHEMA = cv.All(climate.CLIMATE_SCHEMA.extend({
|
||||
cv.Optional(CONF_SWITCH_DATAPOINT): cv.uint8_t,
|
||||
cv.Optional(CONF_TARGET_TEMPERATURE_DATAPOINT): cv.uint8_t,
|
||||
cv.Optional(CONF_CURRENT_TEMPERATURE_DATAPOINT): cv.uint8_t,
|
||||
# cv.Optional(CONF_ECO_MODE_DATAPOINT): cv.uint8_t,
|
||||
cv.Optional(CONF_TEMPERATURE_MULTIPLIER, default=1): cv.positive_float,
|
||||
}).extend(cv.COMPONENT_SCHEMA), cv.has_at_least_one_key(
|
||||
CONF_TARGET_TEMPERATURE_DATAPOINT, CONF_SWITCH_DATAPOINT))
|
||||
|
||||
@@ -38,5 +38,4 @@ def to_code(config):
|
||||
cg.add(var.set_target_temperature_id(config[CONF_TARGET_TEMPERATURE_DATAPOINT]))
|
||||
if CONF_CURRENT_TEMPERATURE_DATAPOINT in config:
|
||||
cg.add(var.set_current_temperature_id(config[CONF_CURRENT_TEMPERATURE_DATAPOINT]))
|
||||
# if CONF_ECO_MODE_DATAPOINT in config:
|
||||
# cg.add(var.set_eco_mode_id(config[CONF_ECO_MODE_DATAPOINT]))
|
||||
cg.add(var.set_temperature_multiplier(config[CONF_TEMPERATURE_MULTIPLIER]))
|
||||
|
||||
@@ -21,28 +21,20 @@ void TuyaClimate::setup() {
|
||||
}
|
||||
if (this->target_temperature_id_.has_value()) {
|
||||
this->parent_->register_listener(*this->target_temperature_id_, [this](TuyaDatapoint datapoint) {
|
||||
this->target_temperature = datapoint.value_int;
|
||||
this->target_temperature = datapoint.value_int * this->temperature_multiplier_;
|
||||
this->compute_state_();
|
||||
this->publish_state();
|
||||
ESP_LOGD(TAG, "MCU reported target temperature is: %d", datapoint.value_int);
|
||||
ESP_LOGD(TAG, "MCU reported target temperature is: %.1f", this->target_temperature);
|
||||
});
|
||||
}
|
||||
if (this->current_temperature_id_.has_value()) {
|
||||
this->parent_->register_listener(*this->current_temperature_id_, [this](TuyaDatapoint datapoint) {
|
||||
this->current_temperature = datapoint.value_int;
|
||||
this->current_temperature = datapoint.value_int * this->temperature_multiplier_;
|
||||
this->compute_state_();
|
||||
this->publish_state();
|
||||
ESP_LOGD(TAG, "MCU reported current temperature is: %d", datapoint.value_int);
|
||||
ESP_LOGD(TAG, "MCU reported current temperature is: %.1f", this->current_temperature);
|
||||
});
|
||||
}
|
||||
// if (this->eco_mode_id_.has_value()) {
|
||||
// this->parent_->register_listener(*this->eco_mode_id_, [this](TuyaDatapoint datapoint) {
|
||||
// this->eco_mode = datapoint.value_bool;
|
||||
// this->compute_state_();
|
||||
// this->publish_state();
|
||||
// ESP_LOGD(TAG, "MCU reported eco mode of: %s", ONOFF(datapoint.value_bool));
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
||||
void TuyaClimate::control(const climate::ClimateCall &call) {
|
||||
@@ -56,30 +48,17 @@ void TuyaClimate::control(const climate::ClimateCall &call) {
|
||||
this->parent_->set_datapoint_value(datapoint);
|
||||
ESP_LOGD(TAG, "Setting switch: %s", ONOFF(datapoint.value_bool));
|
||||
}
|
||||
if (call.get_target_temperature_low().has_value())
|
||||
this->target_temperature_low = *call.get_target_temperature_low();
|
||||
if (call.get_target_temperature_high().has_value())
|
||||
this->target_temperature_high = *call.get_target_temperature_high();
|
||||
|
||||
if (call.get_target_temperature().has_value()) {
|
||||
this->target_temperature = *call.get_target_temperature();
|
||||
|
||||
TuyaDatapoint datapoint{};
|
||||
datapoint.id = *this->target_temperature_id_;
|
||||
datapoint.type = TuyaDatapointType::INTEGER;
|
||||
datapoint.value_int = (int) this->target_temperature;
|
||||
datapoint.value_int = (int) (this->target_temperature / this->temperature_multiplier_);
|
||||
this->parent_->set_datapoint_value(datapoint);
|
||||
ESP_LOGD(TAG, "Setting target temperature: %d", datapoint.value_int);
|
||||
ESP_LOGD(TAG, "Setting target temperature: %.1f", this->target_temperature);
|
||||
}
|
||||
// if (call.get_eco_mode().has_value()) {
|
||||
// this->eco_mode = *call.get_eco_mode();
|
||||
|
||||
// TuyaDatapoint datapoint{};
|
||||
// datapoint.id = *this->eco_mode_id_;
|
||||
// datapoint.type = TuyaDatapointType::BOOLEAN;
|
||||
// datapoint.value_bool = this->eco_mode;
|
||||
// this->parent_->set_datapoint_value(datapoint);
|
||||
// ESP_LOGD(TAG, "Setting eco mode: %s", ONOFF(datapoint.value_bool));
|
||||
// }
|
||||
|
||||
this->compute_state_();
|
||||
this->publish_state();
|
||||
@@ -89,7 +68,6 @@ climate::ClimateTraits TuyaClimate::traits() {
|
||||
auto traits = climate::ClimateTraits();
|
||||
traits.set_supports_current_temperature(this->current_temperature_id_.has_value());
|
||||
traits.set_supports_heat_mode(true);
|
||||
// traits.set_supports_eco_mode(this->eco_mode_id_.has_value());
|
||||
traits.set_supports_action(true);
|
||||
return traits;
|
||||
}
|
||||
@@ -102,8 +80,6 @@ void TuyaClimate::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, " Target Temperature has datapoint ID %u", *this->target_temperature_id_);
|
||||
if (this->current_temperature_id_.has_value())
|
||||
ESP_LOGCONFIG(TAG, " Current Temperature has datapoint ID %u", *this->current_temperature_id_);
|
||||
// if (this->eco_mode_id_.has_value())
|
||||
// ESP_LOGCONFIG(TAG, " Eco Mode has datapoint ID %u", *this->mode_id_);
|
||||
}
|
||||
|
||||
void TuyaClimate::compute_state_() {
|
||||
|
||||
@@ -18,7 +18,9 @@ class TuyaClimate : public climate::Climate, public Component {
|
||||
void set_current_temperature_id(uint8_t current_temperature_id) {
|
||||
this->current_temperature_id_ = current_temperature_id;
|
||||
}
|
||||
// void set_eco_mode_id(uint8_t eco_mode_id) { this->eco_mode_id_ = eco_mode_id; }
|
||||
void set_temperature_multiplier(float temperature_multiplier) {
|
||||
this->temperature_multiplier_ = temperature_multiplier;
|
||||
}
|
||||
|
||||
void set_tuya_parent(Tuya *parent) { this->parent_ = parent; }
|
||||
|
||||
@@ -38,7 +40,7 @@ class TuyaClimate : public climate::Climate, public Component {
|
||||
optional<uint8_t> switch_id_{};
|
||||
optional<uint8_t> target_temperature_id_{};
|
||||
optional<uint8_t> current_temperature_id_{};
|
||||
// optional<uint8_t> eco_mode_id_{};
|
||||
float temperature_multiplier_{1.0f};
|
||||
};
|
||||
|
||||
} // namespace tuya
|
||||
|
||||
@@ -22,8 +22,8 @@ void Tuya::loop() {
|
||||
void Tuya::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "Tuya:");
|
||||
if (this->init_state_ != TuyaInitState::INIT_DONE) {
|
||||
ESP_LOGCONFIG(TAG, " Configuration will be reported when setup is complete. Current init_state: %u", // NOLINT
|
||||
this->init_state_);
|
||||
ESP_LOGCONFIG(TAG, " Configuration will be reported when setup is complete. Current init_state: %u",
|
||||
static_cast<uint8_t>(this->init_state_));
|
||||
ESP_LOGCONFIG(TAG, " If no further output is received, confirm that this is a supported Tuya device.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -41,11 +41,11 @@ void WhirlpoolClimate::transmit_state() {
|
||||
remote_state[18] = 0x08;
|
||||
|
||||
auto powered_on = this->mode != climate::CLIMATE_MODE_OFF;
|
||||
if (powered_on != this->powered_on_assumed_) {
|
||||
if (powered_on != this->powered_on_assumed) {
|
||||
// Set power toggle command
|
||||
remote_state[2] = 4;
|
||||
remote_state[15] = 1;
|
||||
this->powered_on_assumed_ = powered_on;
|
||||
this->powered_on_assumed = powered_on;
|
||||
}
|
||||
switch (this->mode) {
|
||||
case climate::CLIMATE_MODE_AUTO:
|
||||
@@ -215,14 +215,14 @@ bool WhirlpoolClimate::on_receive(remote_base::RemoteReceiveData data) {
|
||||
|
||||
if (powered_on) {
|
||||
this->mode = climate::CLIMATE_MODE_OFF;
|
||||
this->powered_on_assumed_ = false;
|
||||
this->powered_on_assumed = false;
|
||||
} else {
|
||||
this->powered_on_assumed_ = true;
|
||||
this->powered_on_assumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Set received mode
|
||||
if (powered_on_assumed_) {
|
||||
if (powered_on_assumed) {
|
||||
auto mode = remote_state[3] & 0x7;
|
||||
ESP_LOGV(TAG, "Mode: %02X", mode);
|
||||
switch (mode) {
|
||||
|
||||
@@ -28,7 +28,7 @@ class WhirlpoolClimate : public climate_ir::ClimateIR {
|
||||
void setup() override {
|
||||
climate_ir::ClimateIR::setup();
|
||||
|
||||
this->powered_on_assumed_ = this->mode != climate::CLIMATE_MODE_OFF;
|
||||
this->powered_on_assumed = this->mode != climate::CLIMATE_MODE_OFF;
|
||||
}
|
||||
|
||||
/// Override control to change settings of the climate device.
|
||||
@@ -39,15 +39,15 @@ class WhirlpoolClimate : public climate_ir::ClimateIR {
|
||||
|
||||
void set_model(Model model) { this->model_ = model; }
|
||||
|
||||
// used to track when to send the power toggle command
|
||||
bool powered_on_assumed;
|
||||
|
||||
protected:
|
||||
/// Transmit via IR the state of this climate controller.
|
||||
void transmit_state() override;
|
||||
/// Handle received IR Buffer
|
||||
bool on_receive(remote_base::RemoteReceiveData data) override;
|
||||
|
||||
// used to track when to send the power toggle command
|
||||
bool powered_on_assumed_;
|
||||
|
||||
bool send_swing_cmd_{false};
|
||||
Model model_;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import sensor, esp32_ble_tracker
|
||||
from esphome.const import CONF_MAC_ADDRESS, CONF_TEMPERATURE, \
|
||||
UNIT_CELSIUS, ICON_THERMOMETER, UNIT_PERCENT, ICON_WATER_PERCENT, CONF_ID, \
|
||||
from esphome.const import CONF_BATTERY_LEVEL, CONF_MAC_ADDRESS, CONF_TEMPERATURE, \
|
||||
UNIT_CELSIUS, ICON_THERMOMETER, UNIT_PERCENT, ICON_WATER_PERCENT, ICON_BATTERY, CONF_ID, \
|
||||
CONF_MOISTURE, CONF_ILLUMINANCE, ICON_BRIGHTNESS_5, UNIT_LUX, CONF_CONDUCTIVITY, \
|
||||
UNIT_MICROSIEMENS_PER_CENTIMETER, ICON_FLOWER
|
||||
|
||||
@@ -19,6 +19,7 @@ CONFIG_SCHEMA = cv.Schema({
|
||||
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1),
|
||||
cv.Optional(CONF_MOISTURE): sensor.sensor_schema(UNIT_PERCENT, ICON_WATER_PERCENT, 0),
|
||||
cv.Optional(CONF_ILLUMINANCE): sensor.sensor_schema(UNIT_LUX, ICON_BRIGHTNESS_5, 0),
|
||||
cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema(UNIT_PERCENT, ICON_BATTERY, 0),
|
||||
cv.Optional(CONF_CONDUCTIVITY):
|
||||
sensor.sensor_schema(UNIT_MICROSIEMENS_PER_CENTIMETER, ICON_FLOWER, 0),
|
||||
}).extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA).extend(cv.COMPONENT_SCHEMA)
|
||||
@@ -43,3 +44,6 @@ def to_code(config):
|
||||
if CONF_CONDUCTIVITY in config:
|
||||
sens = yield sensor.new_sensor(config[CONF_CONDUCTIVITY])
|
||||
cg.add(var.set_conductivity(sens))
|
||||
if CONF_BATTERY_LEVEL in config:
|
||||
sens = yield sensor.new_sensor(config[CONF_BATTERY_LEVEL])
|
||||
cg.add(var.set_battery_level(sens))
|
||||
|
||||
@@ -14,6 +14,7 @@ void XiaomiHHCCJCY01::dump_config() {
|
||||
LOG_SENSOR(" ", "Moisture", this->moisture_);
|
||||
LOG_SENSOR(" ", "Conductivity", this->conductivity_);
|
||||
LOG_SENSOR(" ", "Illuminance", this->illuminance_);
|
||||
LOG_SENSOR(" ", "Battery Level", this->battery_level_);
|
||||
}
|
||||
|
||||
bool XiaomiHHCCJCY01::parse_device(const esp32_ble_tracker::ESPBTDevice &device) {
|
||||
@@ -50,6 +51,8 @@ bool XiaomiHHCCJCY01::parse_device(const esp32_ble_tracker::ESPBTDevice &device)
|
||||
this->conductivity_->publish_state(*res->conductivity);
|
||||
if (res->illuminance.has_value() && this->illuminance_ != nullptr)
|
||||
this->illuminance_->publish_state(*res->illuminance);
|
||||
if (res->battery_level.has_value() && this->battery_level_ != nullptr)
|
||||
this->battery_level_->publish_state(*res->battery_level);
|
||||
success = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ class XiaomiHHCCJCY01 : public Component, public esp32_ble_tracker::ESPBTDeviceL
|
||||
void set_moisture(sensor::Sensor *moisture) { moisture_ = moisture; }
|
||||
void set_conductivity(sensor::Sensor *conductivity) { conductivity_ = conductivity; }
|
||||
void set_illuminance(sensor::Sensor *illuminance) { illuminance_ = illuminance; }
|
||||
void set_battery_level(sensor::Sensor *battery_level) { battery_level_ = battery_level; }
|
||||
|
||||
protected:
|
||||
uint64_t address_;
|
||||
@@ -29,6 +30,7 @@ class XiaomiHHCCJCY01 : public Component, public esp32_ble_tracker::ESPBTDeviceL
|
||||
sensor::Sensor *moisture_{nullptr};
|
||||
sensor::Sensor *conductivity_{nullptr};
|
||||
sensor::Sensor *illuminance_{nullptr};
|
||||
sensor::Sensor *battery_level_{nullptr};
|
||||
};
|
||||
|
||||
} // namespace xiaomi_hhccjcy01
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
MAJOR_VERSION = 1
|
||||
MINOR_VERSION = 15
|
||||
PATCH_VERSION = '0b3'
|
||||
PATCH_VERSION = '2'
|
||||
__short_version__ = f'{MAJOR_VERSION}.{MINOR_VERSION}'
|
||||
__version__ = f'{__short_version__}.{PATCH_VERSION}'
|
||||
|
||||
@@ -25,6 +25,8 @@ ARDUINO_VERSION_ESP32 = {
|
||||
# See also https://github.com/platformio/platform-espressif8266/releases
|
||||
ARDUINO_VERSION_ESP8266 = {
|
||||
'dev': 'https://github.com/platformio/platform-espressif8266.git',
|
||||
'2.7.4': 'espressif8266@2.6.2',
|
||||
'2.7.3': 'espressif8266@2.6.1',
|
||||
'2.7.2': 'espressif8266@2.6.0',
|
||||
'2.7.1': 'espressif8266@2.5.3',
|
||||
'2.7.0': 'espressif8266@2.5.0',
|
||||
|
||||
@@ -44,7 +44,7 @@ validate_platform = cv.one_of(*ESP_PLATFORMS, upper=True)
|
||||
|
||||
PLATFORMIO_ESP8266_LUT = {
|
||||
**ARDUINO_VERSION_ESP8266,
|
||||
'RECOMMENDED': ARDUINO_VERSION_ESP8266['2.7.2'],
|
||||
'RECOMMENDED': ARDUINO_VERSION_ESP8266['2.7.4'],
|
||||
'LATEST': 'espressif8266',
|
||||
'DEV': ARDUINO_VERSION_ESP8266['dev'],
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ lib_deps =
|
||||
ESPAsyncWebServer-esphome@1.2.7
|
||||
FastLED@3.3.2
|
||||
NeoPixelBus-esphome@2.5.7
|
||||
ESPAsyncTCP-esphome@1.2.2
|
||||
ESPAsyncTCP-esphome@1.2.3
|
||||
1655@1.0.2 ; TinyGPSPlus (has name conflict)
|
||||
6865@1.0.0 ; TM1651 Battery Display
|
||||
6306@1.0.3 ; HM3301
|
||||
|
||||
59
script/bump-docker-base-version.py
Executable file
59
script/bump-docker-base-version.py
Executable file
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
||||
def sub(path, pattern, repl, expected_count=1):
|
||||
with open(path) as fh:
|
||||
content = fh.read()
|
||||
content, count = re.subn(pattern, repl, content, flags=re.MULTILINE)
|
||||
if expected_count is not None:
|
||||
assert count == expected_count, f"Pattern {pattern} replacement failed!"
|
||||
with open(path, "wt") as fh:
|
||||
fh.write(content)
|
||||
|
||||
|
||||
def write_version(version: str):
|
||||
for p in [
|
||||
".github/workflows/ci-docker.yml",
|
||||
".github/workflows/release-dev.yml",
|
||||
".github/workflows/release.yml"
|
||||
]:
|
||||
sub(
|
||||
p,
|
||||
r'base_version=".*"',
|
||||
f'base_version="{version}"'
|
||||
)
|
||||
|
||||
sub(
|
||||
"docker/Dockerfile",
|
||||
r"ARG BUILD_FROM=esphome/esphome-base-amd64:.*",
|
||||
f"ARG BUILD_FROM=esphome/esphome-base-amd64:{version}"
|
||||
)
|
||||
sub(
|
||||
"docker/Dockerfile.dev",
|
||||
r"FROM esphome/esphome-base-amd64:.*",
|
||||
f"FROM esphome/esphome-base-amd64:{version}"
|
||||
)
|
||||
sub(
|
||||
"docker/Dockerfile.lint",
|
||||
r"FROM esphome/esphome-lint-base:.*",
|
||||
f"FROM esphome/esphome-lint-base:{version}"
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('new_version', type=str)
|
||||
args = parser.parse_args()
|
||||
|
||||
version = args.new_version
|
||||
print(f"Bumping to {version}")
|
||||
write_version(version)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main() or 0)
|
||||
@@ -101,6 +101,8 @@ sensor:
|
||||
name: "Xiaomi HHCCJCY01 Illuminance"
|
||||
conductivity:
|
||||
name: "Xiaomi HHCCJCY01 Soil Conductivity"
|
||||
battery_level:
|
||||
name: "Xiaomi HHCCJCY01 Battery Level"
|
||||
- platform: xiaomi_lywsdcgq
|
||||
mac_address: 7A:80:8E:19:36:BA
|
||||
temperature:
|
||||
@@ -280,6 +282,9 @@ text_sensor:
|
||||
service: light.turn_on
|
||||
data:
|
||||
entity_id: light.my_light
|
||||
- homeassistant.tag_scanned:
|
||||
tag: 1234-abcd
|
||||
- homeassistant.tag_scanned: 1234-abcd
|
||||
- platform: template
|
||||
name: "Template Text Sensor"
|
||||
lambda: |-
|
||||
@@ -292,6 +297,21 @@ text_sensor:
|
||||
|
||||
script:
|
||||
- id: my_script
|
||||
mode: single
|
||||
then:
|
||||
- lambda: 'ESP_LOGD("main", "Hello World!");'
|
||||
- id: my_script_queued
|
||||
mode: queued
|
||||
max_runs: 2
|
||||
then:
|
||||
- lambda: 'ESP_LOGD("main", "Hello World!");'
|
||||
- id: my_script_parallel
|
||||
mode: parallel
|
||||
max_runs: 2
|
||||
then:
|
||||
- lambda: 'ESP_LOGD("main", "Hello World!");'
|
||||
- id: my_script_restart
|
||||
mode: restart
|
||||
then:
|
||||
- lambda: 'ESP_LOGD("main", "Hello World!");'
|
||||
|
||||
@@ -316,5 +336,3 @@ interval:
|
||||
- logger.log: "Interval Run"
|
||||
|
||||
display:
|
||||
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@ climate:
|
||||
id: tuya_climate
|
||||
switch_datapoint: 1
|
||||
target_temperature_datapoint: 3
|
||||
temperature_multiplier: 0.5
|
||||
|
||||
switch:
|
||||
- platform: tuya
|
||||
|
||||
Reference in New Issue
Block a user