{"id":349042,"name":"Sunalyzer","description":"A free, open source and vendor independent solar monitoring system. It collects relevant data from your inverter/smart meter and stores them safely in a data base.","url":"https://github.com/borisbrock/sunalyzer","last_synced_at":"2026-07-21T10:30:20.686Z","repository":{"id":56534609,"uuid":"522275603","full_name":"BorisBrock/Sunalyzer","owner":"BorisBrock","description":"A free and open source solar monitoring system.","archived":false,"fork":false,"pushed_at":"2026-06-19T07:54:21.000Z","size":1460,"stargazers_count":80,"open_issues_count":3,"forks_count":23,"subscribers_count":8,"default_branch":"main","last_synced_at":"2026-07-13T07:04:03.243Z","etag":null,"topics":["fronius","pv","solar"],"latest_commit_sha":null,"homepage":"","language":"CSS","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/BorisBrock.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-08-07T17:13:01.000Z","updated_at":"2026-07-10T06:18:45.000Z","dependencies_parsed_at":"2026-03-23T01:01:52.950Z","dependency_job_id":null,"html_url":"https://github.com/BorisBrock/Sunalyzer","commit_stats":{"total_commits":156,"total_committers":2,"mean_commits":78.0,"dds":"0.15384615384615385","last_synced_commit":"0439a424d9c310cc5341087d6b61241e1ed44221"},"previous_names":[],"tags_count":43,"template":false,"template_full_name":null,"purl":"pkg:github/BorisBrock/Sunalyzer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BorisBrock%2FSunalyzer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BorisBrock%2FSunalyzer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BorisBrock%2FSunalyzer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BorisBrock%2FSunalyzer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BorisBrock","download_url":"https://codeload.github.com/BorisBrock/Sunalyzer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BorisBrock%2FSunalyzer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35496719,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-15T02:00:06.706Z","response_time":131,"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"}},"owner":{"login":"BorisBrock","name":"Boris Brock","uuid":"5222025","kind":"user","description":"","email":"","website":null,"location":"Ludwigsburg, Germany","twitter":null,"company":null,"icon_url":"https://avatars.githubusercontent.com/u/5222025?v=4","repositories_count":2,"last_synced_at":"2024-07-10T21:02:53.223Z","metadata":{"has_sponsors_listing":false},"html_url":"https://github.com/BorisBrock","funding_links":[],"total_stars":19,"followers":4,"following":0,"created_at":"2024-07-10T21:02:53.847Z","updated_at":"2024-07-10T21:02:53.847Z","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BorisBrock","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BorisBrock/repositories"},"packages":[],"commits":{"id":1365173,"full_name":"BorisBrock/Sunalyzer","default_branch":"main","total_commits":173,"total_committers":6,"total_bot_commits":1,"total_bot_committers":1,"mean_commits":28.833333333333332,"dds":0.16763005780346818,"past_year_total_commits":5,"past_year_total_committers":3,"past_year_total_bot_commits":1,"past_year_total_bot_committers":1,"past_year_mean_commits":1.6666666666666667,"past_year_dds":0.4,"last_synced_at":"2026-07-15T09:55:11.210Z","last_synced_commit":"ba820a090cd14cec34030cb1d7283ffe9d2b2bfa","created_at":"2023-09-13T14:17:31.699Z","updated_at":"2026-07-15T09:54:55.411Z","committers":[{"name":"Boris Brock","email":"gabrielborisbrock@gmail.com","login":"BorisBrock","count":144},{"name":"Boris Brock","email":"boris@familiebrock.com","login":null,"count":24},{"name":"Sebastian Mezger","email":"s.mezger@gmail.com","login":"smezger","count":2},{"name":"dependabot[bot]","email":"49699333+dependabot[bot]","login":"dependabot[bot]","count":1},{"name":"Steve Palm","email":"n9yty@n9yty.com","login":"n9yty","count":1},{"name":"Darren Horrocks","email":"killallthehumans@gmail.com","login":"bizzehdee","count":1}],"past_year_committers":[{"name":"Boris Brock","email":"gabrielborisbrock@gmail.com","login":"BorisBrock","count":3},{"name":"dependabot[bot]","email":"49699333+dependabot[bot]","login":"dependabot[bot]","count":1},{"name":"Darren Horrocks","email":"killallthehumans@gmail.com","login":"bizzehdee","count":1}],"commits_url":"https://commits.ecosyste.ms/api/v1/hosts/GitHub/repositories/BorisBrock%2FSunalyzer/commits","host":{"name":"GitHub","url":"https://github.com","kind":"github","last_synced_at":"2026-07-20T00:00:13.349Z","repositories_count":6385394,"commits_count":867442381,"contributors_count":35881627,"owners_count":1227606,"icon_url":"https://github.com/github.png","host_url":"https://commits.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://commits.ecosyste.ms/api/v1/hosts/GitHub/repositories"}},"issues_stats":{"full_name":"BorisBrock/Sunalyzer","html_url":"https://github.com/BorisBrock/Sunalyzer","last_synced_at":"2026-06-19T20:00:40.451Z","status":"active","issues_count":9,"pull_requests_count":83,"avg_time_to_close_issue":3200725.6666666665,"avg_time_to_close_pull_request":11817.378048780489,"issues_closed_count":6,"pull_requests_closed_count":82,"pull_request_authors_count":6,"issue_authors_count":9,"avg_comments_per_issue":1.777777777777778,"avg_comments_per_pull_request":0.13253012048192772,"merged_pull_requests_count":81,"bot_issues_count":0,"bot_pull_requests_count":1,"past_year_issues_count":3,"past_year_pull_requests_count":4,"past_year_avg_time_to_close_issue":38250.5,"past_year_avg_time_to_close_pull_request":85326.25,"past_year_issues_closed_count":2,"past_year_pull_requests_closed_count":4,"past_year_pull_request_authors_count":3,"past_year_issue_authors_count":3,"past_year_avg_comments_per_issue":2.0,"past_year_avg_comments_per_pull_request":0.0,"past_year_bot_issues_count":0,"past_year_bot_pull_requests_count":1,"past_year_merged_pull_requests_count":4,"created_at":"2023-09-13T14:17:48.065Z","updated_at":"2026-06-19T20:00:40.451Z","repository_url":"https://issues.ecosyste.ms/api/v1/hosts/GitHub/repositories/BorisBrock%2FSunalyzer","issues_url":"https://issues.ecosyste.ms/api/v1/hosts/GitHub/repositories/BorisBrock%2FSunalyzer/issues","issue_labels_count":{},"pull_request_labels_count":{"dependencies":1,"python":1},"issue_author_associations_count":{"NONE":8,"CONTRIBUTOR":1},"pull_request_author_associations_count":{"OWNER":74,"CONTRIBUTOR":6,"NONE":3},"issue_authors":{"totalscout":1,"rlagerweij":1,"test2a":1,"ThibaultGH":1,"n9yty":1,"ErikZuehlke":1,"rogueeve575":1,"Tchuch0":1,"planet4":1},"pull_request_authors":{"BorisBrock":74,"smezger":4,"n9yty":2,"dependabot[bot]":1,"bizzehdee":1,"rlagerweij":1},"host":{"name":"GitHub","url":"https://github.com","kind":"github","last_synced_at":"2026-07-20T00:00:19.754Z","repositories_count":14860315,"issues_count":32108435,"pull_requests_count":105660183,"authors_count":11351423,"icon_url":"https://github.com/github.png","host_url":"https://issues.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://issues.ecosyste.ms/api/v1/hosts/GitHub/repositories","owners_url":"https://issues.ecosyste.ms/api/v1/hosts/GitHub/owners","authors_url":"https://issues.ecosyste.ms/api/v1/hosts/GitHub/authors"},"past_year_issue_labels_count":{},"past_year_pull_request_labels_count":{"dependencies":1,"python":1},"past_year_issue_author_associations_count":{"NONE":3},"past_year_pull_request_author_associations_count":{"CONTRIBUTOR":2},"past_year_issue_authors":{"rogueeve575":1,"Tchuch0":1,"totalscout":1},"past_year_pull_request_authors":{"bizzehdee":1,"dependabot[bot]":1},"maintainers":[{"login":"BorisBrock","count":74,"url":"https://issues.ecosyste.ms/api/v1/hosts/GitHub/authors/BorisBrock"}],"active_maintainers":[]},"events":{"total":{"ReleaseEvent":1,"DeleteEvent":1,"PullRequestEvent":1,"ForkEvent":6,"WatchEvent":25,"IssueCommentEvent":1,"PushEvent":4},"last_year":{"ReleaseEvent":1,"DeleteEvent":1,"ForkEvent":3,"WatchEvent":6,"IssueCommentEvent":1,"PushEvent":2}},"keywords":["fronius","pv","solar"],"dependencies":[{"ecosystem":"pypi","filepath":"requirements.txt","sha":null,"kind":"manifest","created_at":"2022-08-15T20:31:05.776Z","updated_at":"2022-08-15T20:31:05.776Z","repository_link":"https://github.com/BorisBrock/Sunalyzer/blob/main/requirements.txt","dependencies":[{"id":1819999915,"package_name":"flask","ecosystem":"pypi","requirements":"==2.2.0","direct":true,"kind":"runtime","optional":false},{"id":1819999916,"package_name":"PyYAML","ecosystem":"pypi","requirements":"==6.0.0","direct":true,"kind":"runtime","optional":false},{"id":1819999917,"package_name":"pytest","ecosystem":"pypi","requirements":"==7.1.2","direct":true,"kind":"runtime","optional":false}]},{"ecosystem":"actions","filepath":".github/workflows/docker.yml","sha":null,"kind":"manifest","created_at":"2023-01-20T15:06:22.279Z","updated_at":"2023-01-20T15:06:22.279Z","repository_link":"https://github.com/BorisBrock/Sunalyzer/blob/main/.github/workflows/docker.yml","dependencies":[{"id":7064456391,"package_name":"actions/checkout","ecosystem":"actions","requirements":"v3","direct":true,"kind":"composite","optional":false}]},{"ecosystem":"actions","filepath":".github/workflows/publish.yml","sha":null,"kind":"manifest","created_at":"2023-01-20T15:06:22.293Z","updated_at":"2023-01-20T15:06:22.293Z","repository_link":"https://github.com/BorisBrock/Sunalyzer/blob/main/.github/workflows/publish.yml","dependencies":[{"id":7064456392,"package_name":"actions/checkout","ecosystem":"actions","requirements":"v3","direct":true,"kind":"composite","optional":false},{"id":7064456393,"package_name":"docker/login-action","ecosystem":"actions","requirements":"v2","direct":true,"kind":"composite","optional":false},{"id":7064456394,"package_name":"docker/metadata-action","ecosystem":"actions","requirements":"98669ae865ea3cffbcbaa878cf57c20bbf1c6c38","direct":true,"kind":"composite","optional":false},{"id":7064456395,"package_name":"docker/build-push-action","ecosystem":"actions","requirements":"ad44023a93711e3deb337508980b4b5e9bcdc5dc","direct":true,"kind":"composite","optional":false}]},{"ecosystem":"actions","filepath":".github/workflows/python_lint.yml","sha":null,"kind":"manifest","created_at":"2023-01-20T15:06:22.309Z","updated_at":"2023-01-20T15:06:22.309Z","repository_link":"https://github.com/BorisBrock/Sunalyzer/blob/main/.github/workflows/python_lint.yml","dependencies":[{"id":7064456396,"package_name":"actions/checkout","ecosystem":"actions","requirements":"v3","direct":true,"kind":"composite","optional":false},{"id":7064456397,"package_name":"actions/setup-python","ecosystem":"actions","requirements":"v4","direct":true,"kind":"composite","optional":false}]},{"ecosystem":"actions","filepath":".github/workflows/unit_tests.yml","sha":null,"kind":"manifest","created_at":"2023-01-20T15:06:22.318Z","updated_at":"2023-01-20T15:06:22.318Z","repository_link":"https://github.com/BorisBrock/Sunalyzer/blob/main/.github/workflows/unit_tests.yml","dependencies":[{"id":7064456398,"package_name":"actions/checkout","ecosystem":"actions","requirements":"v3","direct":true,"kind":"composite","optional":false},{"id":7064456399,"package_name":"actions/setup-python","ecosystem":"actions","requirements":"v4","direct":true,"kind":"composite","optional":false}]},{"ecosystem":"docker","filepath":"templates/docker-compose.yml","sha":null,"kind":"manifest","created_at":"2023-01-20T15:06:22.326Z","updated_at":"2023-01-20T15:06:22.326Z","repository_link":"https://github.com/BorisBrock/Sunalyzer/blob/main/templates/docker-compose.yml","dependencies":[{"id":7064456400,"package_name":"borisbrock/sunalyzer","ecosystem":"docker","requirements":"latest","direct":true,"kind":"runtime","optional":false}]}],"score":6.210600077024653,"created_at":"2026-03-21T00:01:08.416Z","updated_at":"2026-07-21T10:30:20.689Z","avatar_url":"https://github.com/BorisBrock.png","language":"CSS","category":"Renewable Energy","sub_category":"Photovoltaics and Solar Energy","monthly_downloads":0,"total_dependent_repos":0,"total_dependent_packages":0,"readme":"# :sunny: Sunalyzer\n\n![Python checks](https://github.com/BorisBrock/Sunalyzer/actions/workflows/python_lint.yml/badge.svg)\n![Unit tests](https://github.com/BorisBrock/Sunalyzer/actions/workflows/unit_tests.yml/badge.svg)\n![Docker build](https://github.com/BorisBrock/Sunalyzer/actions/workflows/docker.yml/badge.svg)\n\nSunalyzer is a free, open source and vendor independent solar monitoring system. It collects relevant data from your inverter/smart meter and stores them safely in a data base.\n\nA modern and beautiful web frontend allows you to visualize the data on any device. The user interface is highly responsive and works great on any screen size, from a small smart phone to a huge PC monitor.\n\nSunalyzer can easily be self hosted on a Raspberry Pi or a NAS by using Docker. It works 100% offline, no cloud is involved. All your data stays under your control.\n\n\u003ca href=\"https://www.buymeacoffee.com/borisbrock\" target=\"_blank\"\u003e\u003cimg src=\"https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png\" alt=\"Buy Me A Coffee\" style=\"height: 60px !important;width: 217px !important;\" \u003e\u003c/a\u003e\n\n![Screenshot](doc/screenshot.png)\n\n## Main Features\n\n- 100% free and open source.\n- Easy to set up and configure (e.g. on a Raspberry Pi or a NAS).\n- Fully local storage of collected data. No cloud or 3rd party involved.\n- Hardware vendor independent.\n- Beautiful and highly dynamic user interface. Desktop and mobile friendly.\n- Visualization of all important values via graphs.\n- Detailled information and statistics with lots of useful information.\n- High resolution historical data (1 minute resolution) is kept.\n- Very compact database: roughly 15mb of storage are required per year.\n- CSV download (manually or via API) of all relevant data.\n\n## Supported Languages\n\nCurrently Sunalyzer provides an **English** and a **German** user interface. The language can be changed on the fly via the user interface.\n\n## Supported Devices\n\nSunalyzer provides integrations for the following device types (inverters/smart meters):\n* Fronius (Symo/Gen24)\n* Sunsynk/Deye (single-phase hybrid inverters, via WiFi/LAN dongle or RS485)\n* Dummy device (for testing purposes)\n\nContributions for the support of additional devices are welcome. Please feel free to reach out to me or submit a pull request directly.\n\n\n## Installation instructions\n\nSunalyzer comes as a self contained and easy to set up Docker container. Thus it can be run on various different platforms. Detailled installation instructions for the Raspberry Pi and Synology DiskStation NAS systems are provided below.\n\n### General Instructions\n\n1. Create a folder called *data* on your host system. This will contain the configuration file and the data base.\n2. Create a configuration YAML file in this data folder. Use [this template](templates/config.yml)] as a starting point. A detailled description of the configuration elements can be found below.\n3. Pull the latest version of the Sunalyzer Docker image from DockerHub.\n4. Create a container based on this image.\n  * The container exposes port 5000. Map this to a port on your host system.\n  * The container exposes a volume called *data*. Map this to the *data* folder on your host system created in step 1.\n5. Make sure your data folder is regularily backed up as it contains the data base!\n6. Start the container. Done!\n\n### Using Docker Compose\n\nIf you are using Docker Compose, create and run a *docker-compose.yml* file like this:\n\n```yaml\nservices:\n  sunalyzer:\n    container_name: sunalyzer\n    image: borisbrock/sunalyzer:latest\n    restart: always\n    ports:\n      - \"8020:5000\"\n    volumes:\n      - /volume1/docker/sunalyzer/data:/data\n```\n\n### Detailled Installation Guide: Synology NAS\n\nIf you want to run Sunalyzer on a Synology NAS, [click here](doc/install_synology.md) for detailled installation instructions.\n\n### Detailled Installation Guide: Raspberry Pi\n\nIf you want to run Sunalyzer on a Raspberry Pi, [click here](doc/install_raspberrypi.md) for detailled installation instructions.\n\n## Configuration\n\nSunalyzer is configured via a YAML file called *config.yml*. This file has to be placed in the data folder before the container is started. An example configuration file can be found [here](templates/config.yml)].\n\n### Configuration Settings Overview\n\n| Setting                       | Description                                                                                         |\n| ----------------------------- | --------------------------------------------------------------------------------------------------- |\n| logging                       | Can be 'normal' (only basic logging) or 'verbose' (verbose logging for debug purposes).             |\n| time_zone                     | The time zone that will be used to generate time stamps for logged data. E.g. \"Europe/Berlin\".      |\n| device:type                   | Name of the device plugin to use. Currently \"Fronius\", \"Sunsynk\" and \"Dummy\" are supported.         |\n| device:start_date             | The date on which the inverter first started production (YYYY-MM-DD).                               |\n| prices:price_per_grid_kwh     | Price for 1 kWh consumed from the grid (e.g. in €).                                                 |\n| prices:revenue_per_fed_in_kwh | Revenue for 1 fed in kWh (e.g. in €).                                                               |\n| server:ip                     | IP address of the web server. Should be set to 0.0.0.0.                                             |\n| server:port                   | Port of the web server. Should be set to 5000.                                                      |\n| grabber:interval_s            | Interval in seconds that the grabber will use to query the inverter/smart meter. Default is 3s.     |\n\nAdditional settings are required depending on the selected device plugin:\n\n#### Fronius\n\n| Setting                       | Description                                                   |\n| ----------------------------- | ------------------------------------------------------------- |\n| fronius::host_name            | IP address or host name of your fronius inverter.             |\n| fronius::has_meter            | True/False - Is there a Fronius smart meter present?          |\n\n#### Sunsynk\n\nSunsynk/Deye single-phase hybrid inverters are read locally (no cloud) over Modbus. Two transports are supported, selected via `sunsynk::connection`:\n\n* `solarman` – talks to the inverter's WiFi/LAN data logger (the \"dongle\") over TCP using the Solarman V5 protocol. This is the default and needs no extra hardware.\n* `modbus_rtu` – talks directly to the inverter's RS485 port via a USB-RS485 adapter. The host serial device must be passed into the container (see below).\n\n| Setting                       | Description                                                                                  |\n| ----------------------------- | -------------------------------------------------------------------------------------------- |\n| sunsynk::connection           | Transport to use: \"solarman\" (WiFi/LAN dongle) or \"modbus_rtu\" (RS485). Default \"solarman\".   |\n| sunsynk::mb_slave_id          | Modbus slave/unit id of the inverter. Default 1.                                             |\n| sunsynk::host_name            | (solarman) IP address or host name of the WiFi/LAN data logger.                              |\n| sunsynk::logger_serial        | (solarman) Serial number of the data logger (printed on the dongle).                         |\n| sunsynk::port                 | (solarman) Solarman V5 TCP port. Default 8899.                                               |\n| sunsynk::serial_port          | (modbus_rtu) Host serial device, e.g. /dev/ttyUSB0 (prefer /dev/serial/by-id/...).           |\n| sunsynk::baudrate             | (modbus_rtu) Serial baud rate. Sunsynk default 9600.                                         |\n| sunsynk::parity               | (modbus_rtu) Serial parity: N, E or O. Default N.                                            |\n| sunsynk::stopbits             | (modbus_rtu) Serial stop bits. Default 1.                                                    |\n| sunsynk::bytesize             | (modbus_rtu) Serial byte size. Default 8.                                                    |\n\n\u003e **Note on registers:** Sunsynk/Deye Modbus register addresses and scales vary by model and firmware. Sunalyzer ships with the de-facto-standard single-phase-hybrid map, but you should verify the values against your own inverter (run with `logging: verbose` to see every decoded value). The register map and references are documented at the top of [backend/devices/Sunsynk.py](backend/devices/Sunsynk.py).\n\n\u003e **RS485 (modbus_rtu) and Docker:** the published image does not include `pymodbus`, so build the image locally instead of pulling it (uncomment `build: .` in your compose file), pass the serial device into the container (`devices: [\"/dev/ttyUSB0:/dev/ttyUSB0\"]`), and grant access to it (`group_add: [\"dialout\"]`). See the commented RS485 section in [templates/docker-compose.yml](templates/docker-compose.yml).\n\n## Deveopment Environment\n\nSunalyzer is currently being developed using the following tools and libraries:\n* **Operating system**: Arch Linux\n* **Development Environment**: Visual Studio Code\n* **Programming languages**: Python 3.12, JavaScript, HTML\n* **Database**: SQlite\n* **Frameworks**: Bootstrap, Chart.js, hammer.js, Fontawesome\n* **DevOps**: flake8, pytest, htmlhint, ESlint\n* **Deployment**: Docker\n","funding_links":["https://www.buymeacoffee.com/borisbrock"],"readme_doi_urls":[],"works":{},"citation_counts":{},"total_citations":0,"keywords_from_contributors":[],"project_url":"https://ost.ecosyste.ms/api/v1/projects/349042","html_url":"https://ost.ecosyste.ms/projects/349042"}