{"id":37070647,"url":"https://github.com/adpeace/boilerio","last_synced_at":"2026-01-14T08:15:03.289Z","repository":{"id":62560311,"uuid":"87484628","full_name":"adpeace/boilerio","owner":"adpeace","description":"A heating control system","archived":false,"fork":false,"pushed_at":"2025-09-04T22:16:46.000Z","size":226,"stargazers_count":6,"open_issues_count":14,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2026-01-03T23:31:03.455Z","etag":null,"topics":["boiler","heating-control","home-automation","thermostat"],"latest_commit_sha":null,"homepage":"https://andyhacks.com","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/adpeace.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-04-06T23:35:29.000Z","updated_at":"2025-09-21T23:25:17.000Z","dependencies_parsed_at":"2022-11-03T14:00:53.061Z","dependency_job_id":"ff7d03de-deb7-484f-b262-546a05c4f58a","html_url":"https://github.com/adpeace/boilerio","commit_stats":{"total_commits":111,"total_committers":2,"mean_commits":55.5,"dds":"0.027027027027026973","last_synced_commit":"e26c74e1f92b6c97a2fb0f2b6f43d8bf9a1d620f"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/adpeace/boilerio","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adpeace%2Fboilerio","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adpeace%2Fboilerio/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adpeace%2Fboilerio/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adpeace%2Fboilerio/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/adpeace","download_url":"https://codeload.github.com/adpeace/boilerio/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adpeace%2Fboilerio/sbom","scorecard":{"id":167573,"data":{"date":"2025-08-11","repo":{"name":"github.com/adpeace/boilerio","commit":"d2a82e404252667c51361eeb78724645fb69e201"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-16T15:20:27.506Z","repository_id":62560311,"created_at":"2025-08-16T15:20:27.507Z","updated_at":"2025-08-16T15:20:27.507Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28413717,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T05:26:33.345Z","status":"ssl_error","status_checked_at":"2026-01-14T05:21:57.251Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["boiler","heating-control","home-automation","thermostat"],"created_at":"2026-01-14T08:15:02.390Z","updated_at":"2026-01-14T08:15:03.245Z","avatar_url":"https://github.com/adpeace.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# The BoilerIO Software Thermostat\n\nBoilerIO can control heating in your home.  Code is provided here to connect\nwith Danfoss RF receivers though other implementations could easily be added,\nand to receive temperature updates over MQTT in a format described later in this\nREADME.\n\nThis has been tested with the Danfoss RF transciever code in the thermostat.git\nrepository at https://github.com/adpeace/thermostat.git.\n\nNo warranty is provided: please be careful if you are messing with your own\nheating system.\n\nFor more information, please see https://andyhacks.com.\n\n## Installation\n\nMore details on installation to be written.  There are several components that\nneed to be configured:\n\n1.  The web application and database, to provide the online component.\n1.  The local scheduler and boiler interface.\n1.  The sensor inputs\n\nYou can install from the repository to get a specific version, such as the\nlatest development version not yet published to PyPI, or install via `pip` from\nPyPI for a recent tested version by running:\n\n```\npip install boilerio\n```\n\nTo install from the git repository, first check it out then install using `pip`:\n\n```\n$ git clone https://github.com/adpeace/boilerio.git\n$ cd boilerio\n$ pip3 install .\n```\n\nUse `-e` to `pip` to install in development mode (i.e. just link to the\nchecked-out source instead of installing it).\n\n### Raspberry Pi Quickstart to get MQTT-based on/off control working\n\nYou can run these steps on a Raspberry Pi with a fresh SD card that has the Buster version of Raspbian.  You can ssh to the Raspberry Pi, then copy/paste these commands into the terminal.  You'll need a transceiver device such as a JeeLink with the `thermostat` firmware (available at https://github.com/adpeace/thermostat) plugged in to use this.\n\n```\nsudo apt install -y python3-pip git\ngit clone https://github.com/adpeace/boilerio.git\ncd boilerio\nsudo pip3 install --upgrade pip  # good practise but not mandatory\nsudo pip3 install .\nsudo mkdir /etc/sensors\nsudo bash -c 'cat \u003e/etc/sensors/config' \u003c\u003cEOF\n[mqtt]\nhost = mqtt_hostname\nuser = mqtt_username\npassword = mqtt_password\n\n[heating]\ninfo_basetopic = heating/zone/info\ndemand_request_topic = heating/zone/demand\nEOF\n```\n\nNow use a text editor such as `nano` to edit `/etc/sensors/config` and replace\nthe MQTT server details with your own.\n\nNow run `boiler_to_mqtt /dev/ttyUSB0` (replacing `/dev/ttyUSB0` with the location\nof the Danfoss transceiver device, e.g. your JeeLink; JeeLink will probably show\nup at that device name though if you don't have other USB devices connected).\n\n## Overview\n\nThe end-to-end application comes in three parts:\n\n1.  The web app backend.  This is the `schedulerweb` Flask app.  It presents a\n    REST API for managing a heating schedule, and is used both by the \"device\"\n    implementation (that translates it into boiler on/off commands and typically\n    runs \"on-site\") and the user interface (which is a web app).  The\n    recommended configuration is for this to be proxied through nginx and run\n    inside uwsgi.  It uses postgres as a storage backend and assumes a database and role exists called `scheduler`.\n\n2.  The thermostat controller.  This is the `scheduler` Python script.  Ensure\n    this daemon is running to control the boiler relay and update the cache of\n    the current temperature in the backend web app.\n\n3.  The web-based UI.  This talks to the schedulerweb app and presents a UI\n    where the current temperature and schedule can be configured.  It is in a separate repository, `boilerio-ui`.\n\n### The web app backend\n\nTo run the scheduler flask application for development, using `flask run`:\n\n```\n$ FLASK_APP=boilerio/schedulerweb/app.py BOILERIO_CONFIG=settings.cfg flask run\n```\n\nThe settings file contains database and other configuration parameters.  An exmaple file is in \"example-settings.cfg\" but you should copy this and update it to suit your needs.\n\nTo run in production, you will need to use a production webserver.  I use uWSGI\nbehind nginx.  Here is an example uWSGI configuration for `schedulerweb`\n(assuming you have the Python package installed) - this can be placed in\n`/etc/uwsgi/apps-available` on Ubuntu's version of uwsgi:\n\n```\n[uwsgi]\nsocket = /var/www/boilerio/thermostat.sock\nmodule = boilerio.schedulerweb:app\nlogto = /var/log/uwsgi/boilerio/thermostat.log\nenv = BOILERIO_SETTINGS=/etc/sensors/settings.cfg\nuid = boilerio\ngid = www-data\nchmod-socket = 664\n```\n\nThis assumes you have placed your settings file in `/etc/sensors/settings.cfg`.\n\n### scheduler: The device/controller\n\nThe local scheduler component provides the timer and thermostat behaviour: it\ngets the target temperature periodically from the web service and controls the\nboiler by sending messages to the boiler\\_to\\_mqtt program.\n\nThe scheduler takes no arguments: the configuration will come from the web\nservice.  In order to actuate a boiler, you will need something listening to\nMQTT to interface to the boiler relays: the boiler_to_mqtt script can do this.\n\n## Boiler control software: boiler\\_to\\_mqtt\n\nThe `boiler_to_mqtt` script implements an MQTT-topic based interface on top\nof the serial protocol provided in the thermostat.git repository.  In short: it\nturns the boiler on and off via MQTT.  The serial interface in thermostat.git is\ndesigned to interact with a Danfoss RF thermostat receiver; if you wanted to use\na different receiver you can substitute a different service.\n\nOrdinarily you'd leave this service running so that other services can turn the\nboiler on/off as needed.\n\nThis service and others in this repository use a common configuration file.  See\nbelow for more information.\n\nYou can send learn packets in a loop with a simple shell loop, if you have the\nmosquitto clients installed and are running the `boiler_to_mqtt.py` script:\n\n```\necho -n \"Learning mode - program boiler then hit enter... \"\nwhile ! read -t 1 ; do\n    mosquitto_pub -h \u003chost\u003e -u \u003cusername\u003e -P \u003cpasswd\u003e -t heating/zone/demand \\\n                  -m '{\"command\": \"L\", \"thermostat\": 47793}'\ndone\n```\n\n## boilersim\n\nThis is a trivial simulator intended to help debug and improve the thermostat.\nIt follows a really simple heating/cooling model and generates a table as\noutput.\n\nTo run, use a command-line such as:\n\n```\n$ boilersim -r 18 19.5 600\n```\n\nThe `-r` option introduces some random noise into the temperature readings\ngenerated by the simulation when passing them to the controller.\n\nThe first positional argument is the starting indoor temperature to simulate.\nThe second argument is the target temperature.  The third argument is\nthe simulated runtime in minutes.\n\nThis program produces logging output to stderr, and a space-separated output to\nstdout.  The output is similar to:\n\n```\n...\n1.0 0 0 17.9964773317 17.9876417779 0 0 0\n...\n```\n\nThe columns are:\n\n1. The time into the simulation, in minutes\n2. The amount of time in that minute that the boiler was on for in the\nsimulation.\n3. The current duty cycle of the boiler in the simulation.\n4. The current simulated room temperature\n5. The fake temperature reading passed to the controller including any error\nintroduced by the `-r` option.\n6. The current value of the proportional term of the PID controller.\n7. The current value of the integral term of the PID controller.\n8. The current value of the differential term of the PID controller.\n\nYou can use the `plot\\_sim.gpi` gnuplot script to plot the output of the\nsimulation.  E.g.:\n\n```\n$ boilersim -r 18 19.5 600  2\u003elog \u003esim_data\n$ gnuplot plot_sim.gpi\n```\n\nThe gnuplot script assumes the simulation output is saved to a file called\n`sim\\_data`.\n\n# Config file\n\nOther than `boilersim`, a config file is needed for the programs here.  This is\nto help make them usable as daemons.\n\n```\n[mqtt]\nhost = raspi.lan\nuser = user\npassword = imnottellingyou\n\n[heating]\n# Various MQTT topic names to use.  These can be anything but are specified in\n# the config in case you have other software that constrains your choices, and\n# ensures they are consistent across apps.\n\ninfo_basetopic = heating/zone/info\ndemand_request_topic = heating/zone/demand\nthermostat_schedule_change_topic = heating/thermostat_control/update\n\nscheduler_db_host = hub.lan\nscheduler_db_name = scheduler\nscheduler_db_user = scheduler\nscheduler_db_password = imnottellingyou\n\nscheduler_url = https://your_url\nscheduler_username = your_user\nscheduler_password = imnottellingyou\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadpeace%2Fboilerio","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadpeace%2Fboilerio","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadpeace%2Fboilerio/lists"}