Skip to content

Repository files navigation

Cerasmarter

CI

Documentation

Documentation tracks the current development firmware. Please open an issue when controller-specific behavior differs from the documented BM1 installation profiles.

Community

You can reach out on Discord to discuss the project and get help from the community.

Purpose and Aim

This project is designed around the idea of having a SCADA-like setup where your command & control server (MQTT-Broker) sends commands and receives the status of the heating. Since the rise of modern and affordable "Smart Radiator Thermostats" we are able to precisely control the room temperature whereas the usual central heating system is only able to react on outside temperatures and doesn't know what the actual demand is like. The heating is only capable of reacting to certain drops in feed and return temperatures and heat up according to setpoints defined by the consumer. This principle is proven and hasn't changed until today.

Cerasmart-er

The Junkers/Bosch "Heatronic" controller of the "Cerasmart" type of boilers (yes they used that term back in pre-2000!) is by itself smart enough to keep your home warm without wasting too much energy, if properly equipped and configured, of course. You won't receive any benefits from this project if you are messing around with the parameters without knowing the concepts of a central heating system. Also if your heating isn't "tuned" to your home it will waste money nonetheless. This also means you can't tell the boiler to perform unreasonable actions because the controller inside the boiler unit is in charge of controlling the actual temperatures within a safe, predefined range that has been set either by the manufacturer or the technician that maintains your heating. We are, however, able to suggest certain temperatures or switch the boiler on and off.

With this project we can at least account for seasonal changes in temperature, humidity and the temperature as we feel it so we can adjust the power demand to what we actually need.

Contribution

There are a lot of different possible setups around and I am happy to accept PRs no matter what they are about.

Just a few examples:

  • You have found an Id and its meaning
  • Something is explained wrong
  • Bugs, of course

Intended Audience

Since the upgrade to a flexible configuration format and the ability to configure things via a web UI, you will be able to tune the system to your needs without knowing much about software development. But you might find yourself in a situation where things don't work as expected. Feel free to open an issue so we can adapt things to your needs.

Disclaimer:

I have sourced the message ids from https://www.mikrocontroller.net/topic/81265 but only process those that are relevant to me. This means you should bring a little bit of patience and basic knowledge about your heating with you so you can actually make decisions about what IDs might be relevant to you or not. You should look at the CAN-Bus configuration on the web UI and the Can Analyzer to sort things out for your heating system. Also you should have Visual Studio Code ready and the extension Platformio installed. We'll talk about that in detail in Prerequisites

A word of warning

You should never, ever manipulate a device that's running on highly volatile substances if you don't know what you are doing. Nobody, in fact, is qualified to work on such a gas heating system but the trained technician that has the right tools and knowledge to modify your heating in a safe manner (read: without blowing up you, himself and the surrounding home). If your are missing a cable to plug in your self-made controller, don't install it yourself. Ask your qualified, local heating technician to do it.

But why? We are talking about a data line!

Simply because installing the bus module or attaching the data cable requires you to open the boiler, remove the cover and also the bezel that covers up the mains voltage supply. In some countries this will also void any insurance coverage if you do it yourself.

Prerequisites

Now that we have sorted out the serious bits, lets check if we got everything together to pull this off...

  1. A compatible Bosch-Junkers central gas heating system with Bosch Heatronic controller and a BM1 Bus Module. BM2 installations are intentionally outside this project's scope.
  2. Access to the data line that exits the bus module. Most of the time you will find a "room thermostat" like TA250 or TA270 which in fact is the control unit for you, the consumer. It won't work with 1-2-4 style room thermostats like the TR200 Again, when in doubt, ask a technician.
  3. Awareness to short circuits and bus failures due to wrong wiring
  4. Direct access to the heating itself in case of problems.
  5. No, really, you shouldn't mess with things that aren't yours
  6. Ideally an ESP32 Kit but if you are just interested in the CAN-Stuff you can of course throw away all the MQTT and WiFi and just use a bog standard arduino.
  7. A MCP2515 + TJA1050 Can-Bus module (i.e. branded "NiRen"). Other boards with different controllers and transceivers may work too.
  8. A MQTT broker (i.e. Mosquitto)
  9. Visual Studio Code & Platform.IO Add-On are recommended!
  10. Optional: DS18B20 Sensors

Installation (Quick Start)

Either clone the repository and build/upload it with PlatformIO, or download the release binaries. For a new board, a board that still contains factory firmware, or a board with an unknown partition table, flash the complete image at address 0x0:

esptool.exe --after hard_reset --chip esp32 --baud 921600 --port <serial port of your device> write_flash --verify 0x0 cerasmarter-complete.bin

The complete image contains the bootloader, Cerasmarter partition table, OTA metadata, firmware, and LittleFS filesystem. Flashing only firmware.bin at 0x10000 does not install the required partition table and will not boot on a board carrying an incompatible factory layout.

After the complete image has provisioned the board once, the component images can be used for updates while retaining the other flash regions:

esptool.exe --after hard_reset --chip esp32 --baud 921600 --port <serial port of your device> write_flash --verify 0x10000 firmware.bin
esptool.exe --after hard_reset --chip esp32 --baud 921600 --port <serial port of your device> write_flash --verify 0x307000 littlefs.bin

These component offsets are valid only with the matching partitions_custom.csv layout. The complete image is intended for first installation or deliberate full recovery; reflashing it also replaces the configuration stored in both NVS and LittleFS.

Release filesystem images contain the credential-free configuration template as /configuration.json; they never contain a developer's device-specific configuration. Its empty WiFi credentials make a new controller start the CERASMARTER access point for provisioning through the web UI.

If everything went well you should see the following output on the console:

Press BOOT within 5 seconds for Setup Mode; hold it for 10 seconds to factory-reset configuration.
Setup Mode not enabled. You can enable it at every time by pressing the "BOOT" button once.
Invalid WiFi configuration. Launching AP mode.
WiFi AP launched. Find me @ 192.168.4.1

A short BOOT-button press during the startup window enters Setup Mode without changing configuration. Holding BOOT continuously for 10 seconds performs a deliberate factory reset: it clears the persistent NVS mirror and all LittleFS configuration copies, then starts the provisioning access point. The frontend and other filesystem assets are retained.

Startup reports filesystem problems separately:

  • LittleFS could not be mounted or formatted indicates a flash-partition or hardware problem.
  • LittleFS was formatted and is empty means the partition recovered but littlefs.bin must be uploaded again.
  • Web frontend is missing means LittleFS exists, but the filesystem image is absent or incomplete.
  • Configuration is missing or invalid starts the setup access point when the frontend is available, so the configuration can be repaired through the web UI.

Now you can connect to the AP ("CERASMARTER" network by default) and modify/import your configuration. A sample configuration is located here. After uploading /configuration.json in the file manager, use Reload Configuration to validate and activate it without a power cycle.

If MDNS is working properly on your end, you will be able to open the web UI using http://cerasmarter/

Web interface preferences

The navigation bar provides English and German language selection and a sun/moon light/dark appearance toggle. Both preferences are stored in the current browser and apply to every web-interface page. On first use, the browser language selects German when appropriate, and the operating-system color preference selects the initial appearance.

Translations are maintained as one JSON resource per locale in data/frontend/i18n/ (en.json, de.json). Keys are grouped by their UI area, for example menu.home, dashboard.system_status, mqtt.prefix, and filemanager.reload. Markup can opt into automatic translation with data-i18n="area.key"; translated attributes use data-i18n-placeholder, data-i18n-title, or data-i18n-aria-label. JavaScript uses translate("area.key", values). English is the fallback locale, and new locales only require a new resource plus an entry in UiLocales.

The CAN Message Analyzer under Utilities receives live bus events independently of verbose console sniffing. It groups traffic by ID, displays configured value names, frame counts, DLCs, mean intervals, last payloads, byte deltas, and common candidate interpretations. Captures can be paused, filtered, limited on screen, and exported as JSON or CSV for comparison. Unknown IDs remain clearly identified. See the CAN Message Analyzer guide for a safe capture workflow, field descriptions, interpretation guidance, and troubleshooting.

Cerasmarter web dashboard

Production-controller capture. The displayed Burner power label was renamed to Feed temperature utilization in the current development UI because it represents the feed-temperature range, not thermal burner output.

The home page is a live heating dashboard organized into heating, mixed-circuit, domestic-hot-water, auxiliary-sensor, runtime-control, and system categories. It presents every value returned by GET /api/runtime, uses equipment-appropriate state icons, and plots a five-minute temperature history with the locally bundled Chart.js 4.5.1 library. No CDN or internet access is required. Utilities > Fallback Heating Control exposes every runtime command accepted through MQTT, including heating-curve, room-reference, boost, fast-heatup, valve-scaling, and hot-water controls. These web fallback commands take effect immediately but are not persisted; stable settings received through MQTT or Home Assistant are stored in RuntimeControls and restored after reboot.

Fallback heating controls

The dashboard data is also available as JSON from GET /api/runtime. Runtime commands can be sent as a partial JSON object to POST /api/control, using the same field names as the heating MQTT payload plus Boost, FastHeatup, and HotWaterSetpoint. Both transports use the same firmware command handlers. See the API reference for request schemas, ranges, persistence behavior, the CAN event stream, and security limitations.

Features

MQTT

Have values where you need them, control on demand. You are able to actively steer the heating towards certain temperatures or modes of operation by publishing and subscribing to MQTT topics from within your favorite MQTT broker (Mosquitto is recommended).

Where?

The topics are described inside /configuration.json on the device or under Configuration > MQTT in the web UI.

How?

To send parameters to the heating controller, you just have to form a JSON and send it to the topic you defined in /configuration.json.

The MQTT section has everything and this is where you define the topics:

    "MQTT": {
        "Server": "1.2.3.4",
        "Port": 1883,
        "User": "mqtt",
        "Password": "mqtt",
        "Topics": {
            "HeatingValues": "cerasmarter/heating/values",
            "HeatingParameters": "cerasmarter/heating/parameters",
            "WaterValues": "cerasmarter/water/values",
            "WaterParameters": "cerasmarter/water/parameters",
            "AuxiliaryValues": "cerasmarter/auxiliary/values",
            "Status": "cerasmarter/status",
            "StatusRequest": "cerasmarter/status/get",
            "Boost": "cerasmarter/boost/set",
            "FastHeatup": "cerasmarter/fastheatup/set"
        }
    },

Example Parameter JSON for setting Heating Parameters:

{
  "Enabled": false,
  "FeedSetpoint": 10,
  "FeedBaseSetpoint": -10,
  "FeedCutOff": 22,
  "FeedMinimum": 10,
  "AuxiliaryTemperature": 11.6,
  "AmbientTemperature": 0,
  "TargetAmbientTemperature": 21,
  "OnDemandBoost": false,
  "OnDemandBoostDuration": 600,
  "FastHeatup": false,
  "Adaption": 0,
  "ValveScaling": 1,
  "ValveScalingMaxOpening": 100,
  "ValveScalingOpening": 75,
  "DynamicAdaption": 1,
  "OverrideSetpoint": false
}

Examples & Detailed Explanation

Heating Parameters

Originally the TAXXX and integrated Heatronic will follow a set of parameters to determine the right feed temperature according to outside temperatures. These values are commonly referred to as "base point" and "end point" and represent a linear regulation by a reference temperature - the environmental temperature on the outside. The original controller will take the desired minimum feed temperature at -15°C as the end point and the required feed temperature at 20°C as the base point. The meaning of base and end point is turned around in this project! Why is that so? Because we are now looking at the environment temperature(s) and we know what the heating can deliver it is easier to understand what we want to achieve. The base point now represents the outside temperature at which the heating should use the maximum possible feed temperature as dialed in by the heating circuit dial on the heating itself The end point is basically the temperature at which the heating should switch off. Linear distibution

In this graph the base point is -10°C and the end point is 20°C meaning at -10°C we need the full power to keep our home warm whereas 20°C is when we don't need it anymore

See FeedBaseSetpoint for base point, FeedCutOff for end point or "cut off" temperature See Example JSON

Night/Economy Mode

Set Enabled to false using the JSON document sent to the configured Heating Parameters topic, the Home Assistant Heating Enabled switch, or Utilities > Fallback Heating Control.

See Example JSON and look out for:

"Enabled": true,

Switch Off/On

See Night/Economy Mode

The manufacturer-defined 10 °C (50 °F) effective feed setpoint represents an off request. Every calculated result below that minimum is normalized to exactly 10 °C before shutdown evaluation, CAN conversion, or transmission. Cerasmarter then switches the heating operation flag off if the effective setpoint remains at 10 °C for General.SetpointOffDelaySeconds. The default grace period is 300 seconds, avoiding short demand changes that could repeatedly cycle the igniter, valves, or pump.

This guard is part of the controller core rather than the Home Assistant integration. It applies equally to MQTT, Home Assistant, WebUI, and locally calculated setpoints. Once active, repeated Enabled: true commands cannot override the off state while the effective feed request remains at 10 °C. A higher effective setpoint clears the guard; clients that explicitly manage Enabled should send it as true with the new demand.

Temperatures remain Celsius internally. Home Assistant performs the equivalent Fahrenheit display conversion when the installation uses imperial units.

Boost

Boost function sets the feed temperature to the maximum reported value (ceraValues.Heating.FeedMaximum) for a selected period of time (default: 300 seconds). This is especially useful when you own electronic or "smart home" thermostats in general which in most cases offer such a boost function. the problem with this "boost" is that although the valve opens up for a few minutes, the heating won't actually deliver the required temperature. A common misunderstanding is that opening the valve to the highest setting will heat more. It will instead only allow for a much higher room temperature as the water flow through the system is almost unchanged. Due to the natural lag of a heating system you should fire this function before you boost a specific radiator.

See Example JSON and look out for:

  "OnDemandBoost": false,
  "OnDemandBoostDuration": 600,

Fast Heatup

Fast Heatup function compares a temperature (commandedValues.Heating.AmbientTemperature) to a given target value (commandedValues.Heating.TargetAmbientTemperature) and sets the feed temperature to maximum (ceraValues.Heating.FeedMaximum) as long as the temperature hasn't reached the target value. It will slowly decrease the feed temperature down from maximum as the target is approached. Fast Heatup Demo

This is how the fast heatup function works visually

See Example JSON and look out for:

  "FastHeatup": false,

set to true to enable this feature

Fallback and Failsafe

The controller starts in local fail-safe mode after every boot and leaves it as soon as MQTT connects. No periodic command heartbeat is required, and the controller does not assume that Node-RED or any other particular automation system is present.

For configuration-file compatibility, the setting remains named CommandTimeoutSeconds. It now defines how long MQTT may remain continuously disconnected before fail-safe mode starts. When that grace period expires, the controller saves the current runtime controls and applies the local fail-safe profile. Reconnecting to MQTT leaves fail-safe mode and restores those saved controls; command frequency does not affect activation.

"FailSafe": {
  "Enabled": true,
  "CommandTimeoutSeconds": 300,
  "StartHour": 5,
  "StartMinute": 30,
  "StopHour": 23,
  "StopMinute": 30,
  "HeatWhenTimeUnknown": true,
  "BasepointTemperature": -10.0,
  "EndpointTemperature": 31.0,
  "MinimumFeedTemperature": 10.0,
  "MaximumFeedTemperature": 55.0
}

On entry, boost, fixed-setpoint override, fast heatup, valve scaling, dynamic adaptation, and manual adaptation are cleared. Between the daily start and stop times the configured heating curve is used and capped at MaximumFeedTemperature. Outside the window heating is disabled. If neither boiler time nor synchronized local time is available, HeatWhenTimeUnknown selects between minimum-temperature heating and heating disabled.

WiFi, MQTT, and NTP recovery are cooperative and bounded; they do not own or suspend the CAN control loop.

Automatic Controller Detection

The controller starts in read-only mode and watches CAN IDs 0x250 through 0x25F for another room controller. As soon as such a message is detected, the Override flag remains false and Cerasmarter does not send control messages. Only after a complete interval with no controller traffic (30 seconds by default, configured by BusMessageTimeout in /configuration.json) does it assume control and set Override to true.

Example:

    "General": {
        "BusMessageTimeout": 30,
        "Debug": false,
        "Sniffing": true
    },

Timeout is set to 30 seconds

You could implement this as a solution to bring in the original controller when something isn't working as expected and you don't have direct access to the ESP. You could switch back on/plug in the original TAxxx unit to run it in OEM mode. Maybe you switch on a relay that triggers the voltage supply for the original controller or you instruct someone to plug the TAxxx unit back in.

External Temperature Sensors

The oneWire and DallasTemperature libraries are included and used to fetch additional temperatures like the return temperature which isn't available on the bus.

Where?

Configured using /configuration.json on the device or Configuration > Temperature Sensors in the web UI.

See Auxiliary Sensors

Dynamic Adaption

Simply put: my heating system is way too powerful and the radiators are not capable of getting rid of the energy fast enough. I figured if I lower the temperature by the difference between return and desired room temperature I can get away with a more dynamic model:

Adaption = Desired target room temperature - feed temperature (+ Manual Adaption)

This means that the setpoint of the feed will be lowered by the difference. You don't have to pump in that much energy when 90% of it returns to the heat exchanger which by itself will always try to steer the feed temperature to the average setpoint.

This kind of adaption is, of course, very simple and rough. As soon as this mode is active, the Adaption value will alter the value accordingly so in my instance I put in additional 5° Adaption so if the temperature would be lowered to around 35° feed, it will be actually set to 40°.

See Example JSON and look out for:

  "Adaption": 0

Calculate yourself

You can do your own calculations and just tell the control to set the temperature accordingly by setting 1|0 or true|false via parameters topic to enable or disable this feature and set the desired FeedSetpoint

See Example JSON and look out for:

  [...]
  "FeedSetpoint": 70,
  [...]
  "OverrideSetpoint": true

Valve-based control

This feature will calculate the desired feed temperature based on the valve opening that is received, mapped using the minimum a valve can be closed (0%) and the maximum (80% for Homematic eTRV-2, set by ValveScalingMaxOpening) to the FeedMinimum plus Adaption and FeedMaximum (reported on the topic defined at HeatingValues within the configuration template). This is the most demand focused function yet because if you always report the most open valve in the circuit, you end up with a very responsive system that will react on demand immediately. This also means that, for example, in the morning when the heat cycle starts, the most open valve will most likely report it is running at the maximum available opening thus raising the feed setpoint to max. As the rooms get warmer and warmer it will eventually throttle and another valve may be higher. This is a self regulating system which will deactivate the influence of outside temperatures. If you want to have the temperature influenced by outside temperature, switch on DynamicAdaption which will then add a value mapped between FeedBaseSetpoint and FeedCutoff. Next set Adaption according to your needs.

Example for dynamic adaption together with valve scaling:

  • Outside Temperature is 5°
  • Basepoint is -15°
  • Endpoint is 31°
  • Feed Adaption is 20
  • Valve Opening: 50%
  • Max Feed: 75°

Map Function: (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min

Adaption Calculation: (Outside - Basepoint) * (Feed Adaption - 0) / (Endpoint - Basepoint) + 0

Example: (5 - -15) * (20 - 0) / (31 - -15) + 0 = 8.7

Feed Calculation: (Valve Opening - Min-Valve Opening) * (Max Feed - (Min-Feed + Adapt. Calc.)) / (Max. Valve - Min. Valve) + (Min. Feed + Adapt. Calc.)

Example: (50 - 0) * (75 - (10 + 8.7)) / (80 - 0) + (10 + 8.7) = 53.89

See Example JSON and look out for:

{
[...]
  //Enable valve scaling
  "ValveScaling": true,
  //The maximum value of a valve
  "ValveScalingMaxOpening": 100,
  //The current valve opening
  "ValveScalingOpening": 75,
[...]
}

Updating

The standard "Arduino OTA" procedure is included which means you can upload the code to your ESP32 without having to plug in the USB cable. See platformio.ini and modify the IP address accordingly.

You can also use the web UI (See: Firmware Update on the menu bar) to upload the firmware.bin and littlefs.bin files to update the firmware and filesystem image.

  • A firmware-only update preserves the existing LittleFS configuration.
  • Every successfully loaded or saved device configuration is mirrored to the separate NVS partition. After a WebUI, PlatformIO, esptool, or programmer-based LittleFS replacement, startup recognizes the credential-free provisioning template and restores the last valid device configuration before normal loading. WebUI filesystem updates still refresh and validate the backup before writing the image.
  • A deliberately uploaded valid /configuration.json remains authoritative and replaces the persistent mirror after it loads. Keep a downloaded backup for manual disaster recovery. To intentionally start over, hold BOOT for 10 seconds during startup; erasing the NVS partition or the whole flash also produces a genuine factory reset.
  • Configuration saves from the web UI are written atomically and verified before they replace the previous file. If validation or writing fails, the previous configuration remains available as a backup.

Telnet Console

Debug info can be retrieved using a very basic telnet implementation. Simply connect to the ESP32 using telnet and watch as the messages flow. You can reboot the ESP by typing reboot and press enter. Be aware you have to type very quickly because this is truly a very minimalistic and barebone implementation of a client-server console communication which is primarily designed to see debug output without having to stand near the esp.

Home Assistant Integration

Cerasmarter uses current MQTT device discovery. No Home Assistant YAML files or separate discovery templates are required.

Set HomeAssistant.Enabled to true, configure the same discovery prefix used by Home Assistant (normally homeassistant), and give every controller a unique DeviceId. After connecting to MQTT, the controller publishes one retained device-discovery document to:

<AutoDiscoveryPrefix>/device/<DeviceId>/config

Home Assistant groups the heating, hot-water, status, and auxiliary-temperature entities under one device. The integration provides temperature and status sensors, binary operating-state sensors, dynamically generated auxiliary-sensor entities, and a read-only sensor for the remaining boost time reported by the controller logic.

Heating controls cover the complete runtime command contract used by the default cerasmarter/heating/parameters topic: heating enablement, requested feed setpoint and direct-setpoint override, heating-curve basepoint/cutoff/minimum, manual and dynamic adaptation, room-reference/target/auxiliary temperatures, valve-scaling enablement/current/max opening, boost duration, boost, and fast heatup. Home Assistant uses individual command topics below cerasmarter/<DeviceId>/Heating/, while legacy clients can continue publishing the existing combined JSON document. Both paths use the same validation and immediately publish the accepted state back to Home Assistant.

Memory, filesystem and flash capacity, chip model and revision, CPU core count, CPU frequency, and auxiliary-sensor connectivity are exposed as diagnostic entities. Home Assistant keeps these on the device's diagnostic card instead of treating them as normal heating controls or measurements.

Discovery assigns purpose-specific Material Design icons to every entity. The Flame Lit binary sensor intentionally has no Home Assistant device class: it therefore reports plain On/Off while using a flame icon whose active color follows the burner state. MQTT discovery supports one static icon per entity, so using different custom glyphs for its on and off states would require a separate Home Assistant template entity.

Runtime state and command topics use cerasmarter/<DeviceId>/..., independently of the discovery prefix. Discovery and state messages are retained, and MQTT Last Will availability marks the device offline if its connection is lost. The controller also listens for Home Assistant's <AutoDiscoveryPrefix>/status birth message and republishes discovery when Home Assistant restarts.

Home Assistant device created through MQTT discovery

Keep DeviceId stable after discovery. If it or the discovery prefix is changed through the web interface, the controller removes its previous retained discovery record and reconnects with the new identity. An old record only needs manual removal if the broker was unavailable during the change.

See the configuration guide for all settings and the API reference for topic behavior.

Hints

  • Automatic takeover is suppressed while messages are observed in the configurable controller-address range. For capture-only installations, enable CAN.ReadOnly in the web interface or configuration file; this hard interlock cannot time out and re-enable transmission.
  • For debug purposes the configuration.General.Debug variable controls whether you see verbose output from routines such as feed-temperature calculation and step-chain progress.
  • Keep in mind that if you are intending to migrate this to an arduino you have to watch out for the OTA feature and float (%f) format parameters within sprintf calls.
  • When OTA is triggered, all connections will be terminated except the one used for OTA because otherwise the update will fail. The MC will keep working.
  • The OTA feature is confirmed working with Arduino IDE and Platform.io but for the latter you have to adapt the settings inside platformio.ini to your preference.

Getting Started

  1. Build and upload the firmware and LittleFS image, or install both binaries from a GitHub release.
  2. Connect to the CERASMARTER access point and open http://192.168.4.1/ if no valid WiFi configuration exists yet.
  3. Configure the device through the web UI, or customize the configuration template and upload it as /configuration.json in the file manager.
  4. Click Reload Configuration after uploading a complete file. The file is validated before it becomes active.
  5. Reconnect using the configured hostname or IP address after WiFi starts.

Do not place a real configuration.json in the repository's data directory when preparing releases. The filesystem build always copies the credential-free file from assets/Templates/Configurations/configuration.json; a device-specific file could contain WiFi and MQTT credentials.

For local USB provisioning only, set CERASMARTER_CONFIG_FILE to an external configuration file while running the buildfs/uploadfs targets. This stages that file in the generated image without adding it to the repository. The pipeline stamps it with "ProvisioningTemplate": false, making the bundled configuration authoritative over an older NVS mirror on first boot; it then becomes the new persistent backup. The GitHub release workflow never sets this override and verifies that release images use the credential-free template stamped true.

This distinction also covers unusual provisioning edge cases: a custom filesystem configuration may intentionally have empty Wi-Fi credentials, but the explicit false marker still prevents it from being replaced. If constructing a LittleFS image outside the supplied pipeline, set the root-level marker yourself. Be aware that custom images contain the selected configuration in recoverable form—including Wi-Fi or MQTT secrets—and must not be published as release artifacts.

Configuration

See the Configuration guide for details.

Dedicated PCB

WIP

Update 09-2022: The bus is very picky about the choice of hardware. Multiple prototypes have been built and tested and further investigation is in progress. Another limitation is the amount of current the built-in power supply can deliver. This is slowing down hardware development even more.

Todo

  • Find a suitable CAN module and library that is able to handle 10kbit/s using the ESP32
  • Debug output over Telnet
  • OTA Update Capability
  • Try not to get mad while searching for the reason why the OTA update is aborting at around 2-8%
  • Collecting IDs and their meaning
  • Getting the calculations right for the feed setpoint
  • Reading and writing MQTT topics
  • Configurable offline fail-safe
  • Taking Weather conditions into account when calculating the feed temperature
  • Also taking indoor temperatures into account
  • Getting the timings right so it doesn't throw off the controller
  • Testing as a standalone solution
  • Example Configuration for Home Assistant
  • Dedicated PCB with all components in place and power supply through the controller
  • Take more intelligent decisions for feed temperatures
  • Restructure code into reusable classes

Special Thanks

Releases

Packages

Contributors

Languages