diff --git a/Makefile b/Makefile index 5133086ba..28938ca9e 100644 --- a/Makefile +++ b/Makefile @@ -4,10 +4,10 @@ ESPHOME_REF = dev .PHONY: html html-strict cleanhtml deploy help webserver Makefile netlify netlify-api api netlify-dependencies svg2png copy-svg2png html: - sphinx-build -M html . _build $(O) + sphinx-build -M html . _build -j auto -n $(O) html-strict: - sphinx-build -M html . _build -W $(O) + sphinx-build -M html . _build -W -j auto -n $(O) cleanhtml: rm -rf "_build/html/*" diff --git a/changelog/v1.7.0.rst b/changelog/v1.7.0.rst index 7991a2c1d..ba4587f12 100644 --- a/changelog/v1.7.0.rst +++ b/changelog/v1.7.0.rst @@ -55,7 +55,7 @@ New Components - The new :doc:`remote receiver ` and :doc:`remote transmitter ` components now allows you to use any 433MHz receivers and senders with ESPHome. Currently, you will need to use the ``raw`` data as described in - :ref:`this guide `, but in the future more protocols will be supported out of the box. + this guide, but in the future more protocols will be supported out of the box. New Features ************ diff --git a/components/climate/custom.rst b/components/climate/custom.rst new file mode 100644 index 000000000..0e5ba9d59 --- /dev/null +++ b/components/climate/custom.rst @@ -0,0 +1,83 @@ +Custom Climate +============== + +This integration can be used to create custom switches in ESPHome +using the C++ (Arduino) API. + +Please first read :doc:`/components/sensor/custom` guide, +the same principles apply here. + +The example below is an example of a custom climate device - all climate devices must override +two methods (:apiclass:`Climate `): + +- ``traits``: This should return a :apiclass:`ClimateTraits ` object + representing the capabilities of the climate device. +- ``control``: This receives a :apiclass:`ClimateCall ` object that contains + the command the user tried to set. + +.. code-block:: cpp + + #include "esphome.h" + + class MyCustomClimate : public Component, public Climate { + public: + void setup() override { + // This will be called by App.setup() + } + void control(const ClimateCall &call) override { + if (call.get_mode().has_value()) { + // User requested mode change + ClimateMode mode = *call.get_mode(); + // Send mode to hardware + // ... + + // Publish updated state + this->mode = mode; + this->publish_state(); + } + if (call.get_target_temperature().has_value()) { + // User requested target temperature change + float temp = *call.get_target_temperature(); + // Send target temp to climate + // ... + } + + } + }; + +(Store this file in your configuration directory, for example ``my_climate.h``) + +And in YAML: + +.. code-block:: yaml + + # Example configuration entry + esphome: + includes: + - my_switch.h + + climate: + - platform: custom + lambda: |- + auto my_custom_climate = new MyCustomClimate(); + App.register_component(my_custom_climate); + return {my_custom_climate}; + + climates: + - name: "My Custom Climate" + +Configuration variables: + +- **lambda** (**Required**, :ref:`lambda `): The lambda to run for instantiating the + climate(s). +- **switches** (**Required**, list): A list of switches to initialize. The length here + must equal the number of items in the ``return`` statement of the ``lambda``. + + - All options from :ref:`Climate `. + +See :apiclass:`Climate ` + +See Also +-------- + +- :ghedit:`Edit` diff --git a/components/cover/custom.rst b/components/cover/custom.rst new file mode 100644 index 000000000..305e1a5f9 --- /dev/null +++ b/components/cover/custom.rst @@ -0,0 +1,87 @@ +Custom Cover +============ + +This integration can be used to create custom covers in ESPHome +using the C++ (Arduino) API. + +Please first read :doc:`/components/sensor/custom` guide, +the same principles apply here. + +The example below is an example of a custom cover - all covers must override +two methods: + +- ``get_traits``: This should return a :apiclass:`CoverTraits ` object + representing the capabilities of the cover. +- ``control``: This receives a :apiclass:`CoverCall ` object that contains + the command the user tried to set. + +.. code-block:: cpp + + #include "esphome.h" + + class MyCustomCover : public Component, public Cover { + public: + void setup() override { + // This will be called by App.setup() + pinMode(5, INPUT); + } + CoverTraits get_traits() override { + auto traits = CoverTraits(); + traits.set_is_assumed_state(false); + traits.set_supports_position(true); + traits.set_supports_tilt(false); + return traits; + } + void control(const CoverCall &call) override { + // This will be called every time the user requests a state change. + if (call.get_position().has_value()) { + float pos = *call.get_position(); + // Write pos (range 0-1) to cover + // ... + + // Publish new state + this->position = pos; + this->publish_state(); + } + if (call.get_stop()) { + // User requested cover stop + } + } + }; + +(Store this file in your configuration directory, for example ``my_cover.h``) + +And in YAML: + +.. code-block:: yaml + + # Example configuration entry + esphome: + includes: + - my_cover.h + + cover: + - platform: custom + lambda: |- + auto my_custom_cover = new MyCustomCover(); + App.register_component(my_custom_cover); + return {my_custom_cover}; + + covers: + - name: "My Custom Cover" + +Configuration variables: + +- **lambda** (**Required**, :ref:`lambda `): The lambda to run for instantiating the + cover(s). +- **covers** (**Required**, list): A list of covers to initialize. The length here + must equal the number of items in the ``return`` statement of the ``lambda``. + + - All options from :ref:`Cover `. + +See :apiclass:`Cover ` + +See Also +-------- + +- :ghedit:`Edit` diff --git a/components/light/custom.rst b/components/light/custom.rst new file mode 100644 index 000000000..dfcabfffa --- /dev/null +++ b/components/light/custom.rst @@ -0,0 +1,81 @@ +Custom Light Output +=================== + +This integration can be used to create custom lights in ESPHome +using the C++ (Arduino) API. + +Please first read :doc:`/components/sensor/custom` guide, +the same principles apply here. + +All internal stuff (like effects, transitions etc) is handled by the light core +and cannot be overriden. Light outputs are only responsible for displaying some state +when asked to do so. + +The example below is an example of a custom light output. + +.. code-block:: cpp + + #include "esphome.h" + + class MyCustomLightOutput : public Component, public LightOutput { + public: + void setup() override { + // This will be called by App.setup() + pinMode(5, INPUT); + } + LightTraits get_traits() override { + // return the traits this light supports + auto traits = LightTraits(); + traits.set_supports_brightness(true); + traits.set_supports_rgb(true); + traits.set_supports_rgb_white_value(false); + traits.set_supports_color_temperature(false); + return traits; + } + + void write_state(LightState *state) override { + // This will be called by the light to get a new state to be written. + float red, green, blue; + // use any of the provided current_values methods + state->current_values_as_rgb(&red, &green, &blue); + // Write red, green and blue to HW + // ... + } + }; + +(Store this file in your configuration directory, for example ``my_light.h``) + +And in YAML: + +.. code-block:: yaml + + # Example configuration entry + esphome: + includes: + - my_cover.h + + light: + - platform: custom + lambda: |- + auto light_out = new MyCustomLightOutput(); + App.register_component(light_out); + return {light_out}; + + lights: + - name: "My Custom Light" + +Configuration variables: + +- **lambda** (**Required**, :ref:`lambda `): The lambda to run for instantiating the + light output(s). +- **lights** (**Required**, list): A list of lights to initialize. The length here + must equal the number of items in the ``return`` statement of the ``lambda``. + + - All options from :ref:`Light `. + +See :apiclass:`Light ` + +See Also +-------- + +- :ghedit:`Edit` diff --git a/github.py b/github.py index 06bbf1208..6e6716488 100644 --- a/github.py +++ b/github.py @@ -265,3 +265,6 @@ def setup(app): app.add_role('ghedit', ghedit_role) app.add_directive('imgtable', ImageTableDirective) app.add_directive('pintable', PinTableDirective) + return {"version": "1.0.0", + "parallel_read_safe": True, + "parallel_write_safe": True} diff --git a/index.rst b/index.rst index f66192dd7..13f32aee6 100644 --- a/index.rst +++ b/index.rst @@ -188,6 +188,7 @@ Light Components NeoPixelBus Light, components/light/neopixelbus, color_lens.svg Light Partition, components/light/partition, color_lens.svg + Custom Light, components/light/custom, language-cpp.svg Looking for WS2811 and similar individually addressable lights? Have a look at the :doc:`FastLED Light `. @@ -236,6 +237,7 @@ Cover Components Template Cover, components/cover/template, description.svg Endstop Cover, components/cover/endstop, electric-switch.svg Time-Based Cover, components/cover/time_based, timer.svg + Custom Cover, components/cover/custom, language-cpp.svg Text Sensor Components ---------------------- @@ -257,6 +259,7 @@ Climate Components Climate Core, components/climate/index, folder-open.svg Bang Bang Controller, components/climate/bang_bang, air-conditioner.svg + Custom Climate, components/climate/custom, language-cpp.svg Misc Components --------------- diff --git a/seo.py b/seo.py index 546e737d9..819b0206b 100644 --- a/seo.py +++ b/seo.py @@ -126,4 +126,6 @@ def setup(app): app.add_node(SEONode, html=(seo_visit, seo_depart)) app.add_directive('redirect', RedirectDirective) app.add_node(RedirectNode, html=(redirect_visit, redirect_depart)) - return {'version': '1.0'} + return {"version": "1.0.0", + "parallel_read_safe": True, + "parallel_write_safe": True} diff --git a/sitemap.py b/sitemap.py index 27743272d..ba8738bba 100644 --- a/sitemap.py +++ b/sitemap.py @@ -7,6 +7,9 @@ def setup(app): app.connect('html-page-context', add_html_link) app.connect('build-finished', create_sitemap) app.sitemap_links = [] + return {"version": "1.0.0", + "parallel_read_safe": True, + "parallel_write_safe": True} def add_html_link(app, pagename, templatename, context, doctree): @@ -18,6 +21,7 @@ def create_sitemap(app, exception): """Generates the sitemap.xml from the collected HTML page links""" root = ET.Element("urlset") root.set("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9") + app.sitemap_links.sort() for link in app.sitemap_links: url = ET.SubElement(root, "url")