{"id":24289268,"url":"https://github.com/rla/cooling","last_synced_at":"2025-10-24T09:51:27.224Z","repository":{"id":15053330,"uuid":"17779458","full_name":"rla/cooling","owner":"rla","description":"System cooling controller with AVR MCU","archived":false,"fork":false,"pushed_at":"2018-11-19T19:10:25.000Z","size":426,"stargazers_count":6,"open_issues_count":0,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-09-25T20:33:08.624Z","etag":null,"topics":["avr","cooling","fan-pwm","mcu","rpm","sensor"],"latest_commit_sha":null,"homepage":"","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/rla.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":"2014-03-15T16:13:53.000Z","updated_at":"2025-02-24T01:54:29.000Z","dependencies_parsed_at":"2022-08-27T22:04:01.400Z","dependency_job_id":null,"html_url":"https://github.com/rla/cooling","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/rla/cooling","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rla%2Fcooling","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rla%2Fcooling/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rla%2Fcooling/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rla%2Fcooling/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rla","download_url":"https://codeload.github.com/rla/cooling/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rla%2Fcooling/sbom","scorecard":{"id":778449,"data":{"date":"2025-08-11","repo":{"name":"github.com/rla/cooling","commit":"317ef132c82311414b4e466f3ab2c6d880f9d1c6"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.2,"checks":[{"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":"Code-Review","score":1,"reason":"Found 4/24 approved changesets -- score normalized to 1","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":"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":"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":"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":"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"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 10 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-23T04:15:54.833Z","repository_id":15053330,"created_at":"2025-08-23T04:15:54.833Z","updated_at":"2025-08-23T04:15:54.833Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280776484,"owners_count":26388950,"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-10-24T02:00:06.418Z","response_time":73,"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":["avr","cooling","fan-pwm","mcu","rpm","sensor"],"created_at":"2025-01-16T10:51:46.051Z","updated_at":"2025-10-24T09:51:27.187Z","avatar_url":"https://github.com/rla.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# avrcooling\n\nPC cooling controller for rotary cooling devices (fans/pumps). It has\nthe following features:\n\n * Supports 4 cooling devices.\n * Can disable devices that still run on minimal PWM.\n * Monitors devices RPM.\n * RPM measurement supports pulse stretching.\n * Supports 2 thermal sensors.\n * Error signal output.\n * Can be controlled/queried over RS-232 interface.\n * Command-line client to query/debug/control the device.\n * Hardware design and source code is MIT-licensed.\n\n### Control algorithm\n\nThe control algorithm uses 2 [decision tables](http://en.wikipedia.org/wiki/Decision_table),\none per thermal sensor. Table rows contain the following information:\n\n * enabled - whether the control row is enable.\n * min_temp - lower bound for activating the control row.\n * max_temp - upper bound for activating the control row.\n * affect_fan0 - whether to apply the row to fan 0.\n * affect_fan1 - whether to apply the row to fan 1.\n * affect_fan2 - whether to apply the row to fan 2.\n * affect_fan3 - whether to apply the row to fan 3.\n * fan0_pwm - PWM value to apply for fan 0.\n * fan1_pwm - PWM value to apply for fan 1.\n * fan2_pwm - PWM value to apply for fan 2.\n * fan3_pwm - PWM value to apply for fan 3.\n\nThere are 5 rows in each table. The first row with\nmin_temp...max_temp range including the current temperature is used for\napplying the control values.\n\nAll cooling fans start initially in disabled state and with\n0 PWM. When a fan PWM is set to a value greater than 0 then the fan power is\nenabled. When PWM is set to 0 then the fan is also powered down.\n\nControl table rows are checked periodically. The rows can be\nread and updated using the command-line PC app described below.\n\n## Project structure\n\nThe project is divided into 3 subdirectories:\n\n * `avr` - source for microcontroller binary.\n * `hw` - physical hardware design.\n * `pc` - NodeJS command-line app for communication.\n\n## Hardware\n\n### Pin allocation\n\n![Atmega88 pinout](hw/pins.png)\n\n * pin  1: reset, connected to VCC and protected by zener diode\n * pin  2: USART RX line (pullup?)\n * pin  3: USART TX line\n * pin  4: PD2, Error signal output\n * pin  5: PD3, OC2B, fan 4 PWM output\n * pin  6: PD4, not connected\n * pin  7: VCC\n * pin  8: GND\n * pin  9: XTAL 1\n * pin 10: XTAL 2\n * pin 11: PD5, OC0B, fan 2 PWM output\n * pin 12: PD6, OC0A, fan 1 PWM output\n * pin 13: PD7, not connected\n * pin 14: PB0, fan 1 enable\n * pin 15: PB1, fan 2 enable\n * pin 16: PB2, fan 3 enable\n * pin 17: PB3, fan 3 PWM output\n * pin 18: PB4, fan 4 enable\n * pin 19: PB5, not connected\n * pin 20: AVCC, connected to VCC through low-pass filter L1/C13\n * pin 21: AREF, analog reference, decoupled with 100nF cap C10\n * pin 22: GND\n * pin 23: PC0, ADC0, temperature sensor 1 input, low-pass filter R5/C7\n * pin 24: PC1, ADC1, temperature sensor 2 input, low-pass filter R3/C8\n * pin 25: PC2, fan 1 RPM input, pull-up, low-pass filter R10/C9\n * pin 26: PC3, fan 2 RPM input, pull-up, low-pass filter R9/C11\n * pin 27: PC4, fan 3 RPM input, pull-up, low-pass filter R8/C12\n * pin 28: PC5, fan 4 RPM input, pull-up, low-pass filter R7/C14\n\n### Port directions\n\n#### Port B\n\n * PB0 - output (fan 1 enable)\n * PB1 - output (fan 2 enable)\n * PB2 - output (fan 3 enable)\n * PB3 - output (fan 3 PWM)\n * PB4 - output (fan 4 enable)\n * PB5 - output (not connected)\n * PB6 - output (overriden by xtal)\n * PB7 - output (overriden by xtal)\n\n#### Port C\n\n * PC0 - input (ADC)\n * PC1 - input (ADC)\n * PC2 - input (fan 1 RPM, pull-up)\n * PC3 - input (fan 2 RPM, pull-up)\n * PC4 - input (fan 3 RPM, pull-up)\n * PC5 - input (fan 4 RPM, pull-up)\n * PC6 - input (default reset config)\n * PC7 - not in circuit/registry\n\n#### Port D\n\n * PD0 - output (overriden by USART)\n * PD1 - output (overriden by USART)\n * PD2 - output (error)\n * PD3 - output (fan 4 PWM)\n * PD4 - output (not connected)\n * PD5 - output (fan 2 PWM)\n * PD6 - output (fan 1 PWM)\n * PD7 - output (not connected)\n\n### Full schematics\n\nFull schematics in Eagle format can be found in the file `hw/schematics.sch`.\n\n![Full schematics](hw/schematics.png)\n\n#### Part list\n\n * C1 10uF/16V\n * C2 100nF/63V 5mm\n * C3, C4 22pF/63V 2.54mm\n * C5 100nF/63V 5mm\n * C6 10uF/16V 5mm\n * C7, C8 10nF/100V 5mm\n * C9, C11, C12, C14 10nF/63V 5mm\n * C10 100nF/63V 5mm\n * C13 100nF/63V 5mm\n * D1 5.1V zener 7.62mm\n * D2, D3, D4, D5 2N4007\n * IC1 Atmega88 DIP28\n * R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11 10k\n * Q1 12MHz\n * Q2, Q4, Q6, Q8 2N7000\n * Q3, Q5, Q7, Q9 IRF9530\n * L1 10uH\n * X3 molex power connector, [Farnell product page](http://uk.farnell.com/jsp/search/productdetail.jsp?SKU=1391827)\n * X6, X7, X8, X9 molex 47053-1000 headers, [Farnell product page](http://uk.farnell.com/jsp/search/productdetail.jsp?SKU=2313705)\n\n### Board layout\n\nBoard layout in Eagle format can be found in the file `hw/board.brd`. Layout\nsuitable for tone-transfer can be found in the PDF file `hw/board.pdf`.\n\n![Board layout](hw/board.png)\n\nPhoto of 2 completed units:\n\n![2 completed units](hw/photo.jpg)\n\n### Fan connectors\n\n4-wire connectors are standardized in the [specification](http://www.formfactors.org/developer%5Cspecs%5C4_Wire_PWM_Spec.pdf).\nConnector pinout with typical wire colors is:\n\n * 1 - GND - black\n * 2 - 12V - yellow\n * 3 - RPM - green\n * 4 - PWM - blue\n\nThe max fan current is limited by switch MOSFET channel resistance in ON mode.\nThis is about 0.3 Ohms. Max dissipation of 1W gives the max current of about 1.9A.\n\n![4-pin molex](hw/molex_4pin.png)\n\n#### 3-wire connectors\n\n3-wire connectors lack PWM signal but are otherwise compatible with\n4-wire headers. Pinout:\n\n * 1 - GND - black\n * 2 - 12V - red\n * 3 - RPM - yellow\n\nWhile a 3-wire fan lacks PWM control, it can still be made variable-speed by\nmodulating the supply voltage. This can be implemented with the following\ncircuit:\n\n![3-wire to 4-wire adapter](hw/adapter.png)\n\n#### Temp. sensor connectors\n\nThese connect MCP9700 to the board. There can be up to 2 sensors\nconnected. The system assumes 0.5V offset and 10mv per °C. This can be\nchanged by recompiling the firmware.\n\n * 1 - sensor output\n * 2 - sensor power (5V)\n * 3 - GND\n\n#### Error signal connector\n\nError signal is set high whenever an enabled fan's RPM\nreads 0. The signal comes directly from MCU and cannot\nbe directly loaded with higher current than 40mA.\n\n * 1 - error signal\n * 2 - GND\n\n#### RS-232 interface\n\nThe RS-232 interface is used for updating the control line tables and\nfor debugging the device. The connector is denoted as X1 on schematics\nand board and has the following pinout:\n\n * 1 - TX line\n * 2 - RX line\n * 3 - GND\n\nA level translator has to be used for connecting the device to PC. PC\nuses signal levels -12V/+12V while the device uses normal TTL levels 0V/5V.\n\nA level translator can be built using the [MAX232](http://www.ti.com/lit/ds/symlink/max232.pdf)\nchip or using a prebuilt module/cable/converter. There are various circuits and\nbuilding instructions on the Internet.\n\n### Compiling firmware\n\nThe project contains a Makefile that includes build targets\nwith [avr-gcc](http://www.nongnu.org/avr-libc/) compiler.\n\nTo build the HEX binary for the controller:\n\n    cd avr\n    make\n\nIf [avrdude](http://www.nongnu.org/avrdude/) is installed then the hex file\ncan be burned into the device with the command:\n\n    make burn\n\n### Fuses\n\n * Clock: Full-swing crystal, BOD enabled\n * BOD 4.3V\n\n#### Low fuse\n\n * CKDIV8 1 (unprogrammed)\n * CKOUT 1 (unprogrammed)\n * SUT1 0 (crystal, BOD enabled)\n * SUT0 1 (crystal, BOD enabled)\n * CKSEL3 0\n * CKSEL2 1\n * CKSEL1 1\n * CKSEL0 1\n\nCKSEL is for full-swing crystal osc. lfuse total 11010111 = 0xd7.\n\n#### High fuse\n\n * RSTDISBL 1 (unprogrammed)\n * DWEN 1 (unprogrammed)\n * SPIEN 0 (programmed)\n * WDTON 1 (unprogrammed)\n * EESAVE 1 (unprogrammed)\n * BODLEVEL2 1\n * BODLEVEL1 0\n * BODLEVEL0 0\n\nhfuse total 11011100 = 0xdc.\n\nIf avrdude is installed then correct fuses can be burned\nusing the command:\n\n    make burn-fuse\n\n## Client\n\nThe client application is used for updating the control table lines\nand for debugging the device.\n\nClient options and supported commands:\n\n```\nUsage: avrcooling --port \u003cport\u003e --command \u003ccommand\u003e [arguments]\nRecognized commands:\n  disable0       disable fan 0\n  disable1       disable fan 1\n  disable2       disable fan 2\n  disable3       disable fan 3\n  echo           sends and receives the given byte\n  enable0        enable fan 0\n  enable1        enable fan 1\n  enable2        enable fan 2\n  enable3        enable fan 3\n  nostretch0     disable pulse stretch for fan 0\n  nostretch1     disable pulse stretch for fan 1\n  nostretch2     disable pulse stretch for fan 2\n  nostretch3     disable pulse stretch for fan 3\n  pwm0_get       query fan 0 PWM level (0-255)\n  pwm0_set       set fan 0 PWM (0-255)\n  pwm1_get       query fan 1 PWM level (0-255)\n  pwm1_set       set fan 1 PWM (0-255)\n  pwm2_get       query fan 2 PWM level (0-255)\n  pwm2_set       set fan 2 PWM (0-255)\n  pwm3_get       query fan 3 PWM level (0-255)\n  pwm3_set       set fan 3 PWM (0-255)\n  rpm0           query fan 0 RPM\n  rpm1           query fan 1 RPM\n  rpm2           query fan 2 RPM\n  rpm3           query fan 3 RPM\n  stretch0       enable pulse stretch for fan 0\n  stretch1       enable pulse stretch for fan 1\n  stretch2       enable pulse stretch for fan 2\n  stretch3       enable pulse stretch for fan 3\n  stretch_info   query pulse stretch settings\n  temp0          query sensor 0 temperature\n  temp0_line_get get control table line (0-4) for sensor 0\n  temp0_line_set set control table line (0-4) for sensor 0\n  temp1          query sensor 1 temperature\n  temp1_line_get get control table line (0-4) for sensor 1\n  temp1_line_set set control table line (0-4) for sensor 1\n\n```\n\n### Debugging\n\nSet environment variable `DEBUG=*` and run the command.\n\n    DEBUG=* avrcooling ...\n\n### Installation\n\nAssuming that you have [NodeJS](https://nodejs.org/) installed:\n\n    npm install -g avrcooling\n\n### Protocol\n\nThe client-device communication protocol terminates messages with line ends.\nData on individual lines is encoded in the hex encoding.\n\nDecoded commands have the following format:\n\n    [command_byte, arguments..., checksum_byte]\n\nResponses have the following format:\n\n    [response_ok, response arguments..., checksum_byte]\n\nor\n\n    [response_fail, checksum_byte]\n\nor\n\n    [command_checksum_fail, checksum_byte]\n\nMultibyte integers are sent in big-endian format. Maximum decoded message length is 10 bytes.\nThe detailed description of the protocol is found in [pc/lib/commands.js](pc/lib/commands.js).\n\nThe checksum computation uses the Pearson hash algorithm:\n\u003chttp://en.wikipedia.org/wiki/Pearson_hashing\u003e. The constants\ntable can be found in [avr/src/pearson.c](avr/src/pearson.c).\n\n## Changelog\n\n * 2018-11-11 Do not reset PWM on disable. Implement missing get-pwm command.\n   Reset RPM only on timeout preventing sporadic 0 RPM responses. Update RPM\n   atomically preventing potentially corrupted responses due to data race.\n * 2016-01-31 BOD (brown-out detection) enabled.\n * 2015-03-24 Pulse stretching is implemented. Client code is finished.\n * 2014-07-27 Client code is mostly working.\n * 2014-07-17 AVR code is mostly working.\n * 2014-02-01 Physical hardware design is ready.\n\n## Known issues\n\n * Max ADC input voltage is 1.1V when the internal reference is selected (by default).\n * Temperature sensor MCP9700 needs 100nF decoupling cap at the sensor to ensure\n   stable operation.\n\n## License\n\nThe MIT License. See the LICENSE file.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frla%2Fcooling","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frla%2Fcooling","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frla%2Fcooling/lists"}