{"id":13894057,"url":"https://github.com/rpj/zw","last_synced_at":"2026-04-12T15:53:42.188Z","repository":{"id":52581548,"uuid":"200460906","full_name":"rpj/zw","owner":"rpj","description":"ZeroWatch, an ESP32-based Redis-watcher and info-displayer","archived":false,"fork":false,"pushed_at":"2021-04-25T00:12:21.000Z","size":41,"stargazers_count":2,"open_issues_count":6,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-29T16:42:00.627Z","etag":null,"topics":["arduino","esp32","esp32-arduino","redis","tm1637"],"latest_commit_sha":null,"homepage":"https://rpjios.com","language":"C++","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/rpj.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}},"created_at":"2019-08-04T07:04:21.000Z","updated_at":"2023-04-17T20:54:17.000Z","dependencies_parsed_at":"2022-09-06T20:30:47.854Z","dependency_job_id":null,"html_url":"https://github.com/rpj/zw","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/rpj/zw","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rpj%2Fzw","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rpj%2Fzw/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rpj%2Fzw/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rpj%2Fzw/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rpj","download_url":"https://codeload.github.com/rpj/zw/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rpj%2Fzw/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268378965,"owners_count":24240907,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-02T02:00:12.353Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["arduino","esp32","esp32-arduino","redis","tm1637"],"created_at":"2024-08-06T18:01:22.790Z","updated_at":"2026-04-12T15:53:37.150Z","avatar_url":"https://github.com/rpj.png","language":"C++","funding_links":[],"categories":["C++"],"sub_categories":[],"readme":"# ZeroWatch\n\nA highly-configurable ESP32-based Redis-watcher and TM1637-displayer, with OTA capability.\n\nCurrently driving stuff like [this](https://twitter.com/rpjios/status/1155609352528486400) and [this](https://twitter.com/rpjios/status/1100077092287344642):\n\n![version 2](https://pbs.twimg.com/media/EAmMSaPVUAEKYcl?format=jpg\u0026name=small)\n![version 1](https://pbs.twimg.com/media/D0RCGcvVAAArx5x?format=jpg\u0026name=small)\n\n## Dependencies\n\n* [ArduinoJson](https://arduinojson.org/) **version 5**\n* [avishorp's TM1637 driver](https://github.com/avishorp/TM1637)\n* [Arduino-Redis](http://arduino-redis.com/) version [2.1.1](https://github.com/electric-sheep-co/arduino-redis/releases/tag/2.1.1) or later\n\n## Provisioning\n\nUnits must be provisioned with [critical datum](https://github.com/rpj/zw/blob/master/zw_provision.h#L10-L16), written to EEPROM, before they will behave correctly.\n\nTo do so, fill in the aforementioned fields appropriately, set [`ZERO_WATCH_PROVISIONING_MODE` to `1`](https://github.com/rpj/zw/blob/master/zw_provision.h#L7) and upload to your ESP32 while monitoring serial (at [this baud rate](https://github.com/rpj/zw/blob/master/zero_watch.ino#L18)). There are wait-points that allow you to remove power for the unit before data is written.\n\nMost critical of these values is [hostname](https://github.com/rpj/zw/blob/master/zw_provision.h#L10), which is limited to 32 characters in length and *must be unique across your network*. All references to `HOSTNAME` elsewhere in this document refer to this data. \n\nNone of the remaining fields must be longer than [`PSTRING_LENGTH_LIMIT`](https://github.com/rpj/zw/blob/master/zw_provision.cpp#L79) bytes and `ZWPROV_REDIS_PORT` must always only be two bytes (`sizeof(uint16_t)`).\n\nOnce provisioned, the unit will halt forever, so to return it to normal behavior: unset `ZERO_WATCH_PROVISIONING_MODE` and all `ZWPROV_*` fields, rebuild and reflash. That's it!\n\n## Configuration\n\nMost of the behavior, save for the [display specifications](https://github.com/rpj/zw/blob/master/zw_displays.cpp#L67-L78) (which will one day be configurable as well), is configurable at runtime via the Redis instance the unit connects to.\n\nSpecifically, a [number of fields](https://github.com/rpj/zw/blob/master/zw_common.h#L7-L13) are exposed as `HOSTNAME:config:*` keys for which any written (valid) value will be honored on the next refresh cycle.\n\nThere is also a [control point](https://github.com/rpj/zw/blob/master/zero_watch.ino#L131) key at `HOSTNAME:config:controlPoint`, a [metadata getter](https://github.com/rpj/zw/blob/master/zero_watch.ino#L69) at `HOSTNAME:config:getValue` and the [OTA update configuration](https://github.com/rpj/zw/blob/master/zero_watch.ino#L177) key at `HOSTNAME:config:update`.\n\n## OTA\n\nSet [`ZWPROV_OTA_HOST`](https://github.com/rpj/zw/blob/master/zw_provision.h#L16) when provisioning to an HTTP host visible to the unit and this will be combined with the update metadata's `url` component to produce the fully-qualified URL for acquisition of the update binary.\n\nThe aforementioned metadata must be written to `HOSTNAME:config:update` as as JSON object consisting of: `url`, `md5`, `size`, and `otp` (a [\"one-time password\"](https://github.com/rpj/zw/blob/master/zw_otp.cpp)), e.g.:\n\n```js\n{\n    \"url\":  \"zero_watch_updates/zero_watch-v0.2.0.6.ino.bin\",\n    \"md5\":  \"1a6f92066b6e3a63362c6b376fbc438d\",\n    \"size\": 924960,\n    \"otp\": 123\n}\n```\n\nOn the next refresh cycle, this data will be picked up and acted upon. Monitor serial or Redis (depending on `HOSTNAME:config:publishLogs`) for logging. Upon successful update, the unit will delete `HOSTNAME:config:update` and reset to the new software (after a [small, build-time configurable delay](https://github.com/rpj/zw/blob/master/zw_ota.h#L6)).\n\nPre-built images of recent versions are available [here](https://ota.rpjios.com/), but only via HTTPS so as to be unusable as `ZWPROV_OTA_HOST`. You should only be deploying this type of insecure OTA on a secure local or virtual private network, anyway! :smile:\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frpj%2Fzw","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frpj%2Fzw","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frpj%2Fzw/lists"}