{"id":17055591,"url":"https://github.com/tuna-f1sh/node-flipdot","last_synced_at":"2025-04-12T17:10:51.668Z","repository":{"id":44007764,"uuid":"97121243","full_name":"tuna-f1sh/node-flipdot","owner":"tuna-f1sh","description":"Node module to drive Hanover Flip Dot displays","archived":false,"fork":false,"pushed_at":"2022-07-08T11:37:33.000Z","size":112,"stargazers_count":46,"open_issues_count":1,"forks_count":9,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-05-02T04:42:49.910Z","etag":null,"topics":["ascii-art","figlet","flipdot","nodejs"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tuna-f1sh.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":"2017-07-13T12:41:14.000Z","updated_at":"2024-04-06T22:14:05.000Z","dependencies_parsed_at":"2022-07-09T14:46:25.002Z","dependency_job_id":null,"html_url":"https://github.com/tuna-f1sh/node-flipdot","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuna-f1sh%2Fnode-flipdot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuna-f1sh%2Fnode-flipdot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuna-f1sh%2Fnode-flipdot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuna-f1sh%2Fnode-flipdot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tuna-f1sh","download_url":"https://codeload.github.com/tuna-f1sh/node-flipdot/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248602313,"owners_count":21131616,"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","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":["ascii-art","figlet","flipdot","nodejs"],"created_at":"2024-10-14T10:18:38.876Z","updated_at":"2025-04-12T17:10:51.648Z","avatar_url":"https://github.com/tuna-f1sh.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Hanover FlipDot Display RS485 Driver\n\n![Demo gifv](http://i.imgur.com/wRxU6VV.gif)\n\nNode.js driver for the [Hanover Flip-Dot Display](http://dbiw.net/HanoverDisplays/Flip_Dot_Manual_vB.pdf). Designed to be used with [USB-RS485 dongle](https://www.ebay.co.uk/sch/i.html?_from=R40\u0026_trksid=p5197.m570.l1313\u0026_nkw=usb+rs485\u0026_sacat=See-All-Categories).\n\nFor a usage demo, see the [emulated web app\ncontroller](http://flipdot.jbrengineering.co.uk) I made for my\ndisplay to show at a local art trail. [Source\nlink](https://github.com/tuna-f1sh/flippy-flipdot-web).\n\nSee my blog post and YouTube video for a technical run down: [https://engineer.john-whittington.co.uk/2017/11/adventures-flippy-flip-dot-display/](https://engineer.john-whittington.co.uk/2017/11/adventures-flippy-flip-dot-display/)\n\n## Features\n\n* Figlet ascii art based text renderer, including font selection, offset and\n  inversion.\n* Automatic scrolling text.\n* Automatic queueing of data and frame management.\n* Matrix based data input (\\[x\\]\\[y\\]).\n\n## Installation \u0026 Usage\n\nAs a module:\n```\nnpm install flipdot-display # see below sections on integration\n```\n\nAs a CLI application:\n```\nnpm install -g flipdot-display\nflipdot --help # send text bin (args are optional)\nflipdot-clock --help # send clock bin (args are optional)\n```\n\n### Debug\n\n`DEBUG=* node examples/test.js`\n\n### Important Notes\n\n* The **address** of your display (defualt 0x05 - arbitary but matches mine) must be correct otherise the display will not display the data. Find the correct address through trial and error or by taking the back off and reading the potentiometer (RHS) position\n* The **number of columns and rows** (default 56x7) must be correct for your display otherwise the message length will be incorrect - the Hanover display may not acknowledge or display the incorrect message length.\n\n## Methodology\n\nThe Hanover Flip-Dot display expects ascii chars representing the hexadecimal\nbytes; bytes being every 8 rows of dots. For example, an eight row column:\n\n```\n. = 1 =\u003e 0xF5 =\u003e ['F', '5'] =\u003e [0x46, 0x35]\n| = 0\n. = 1\n| = 0\n. = 1\n. = 1\n. = 1\n. = 1\n```\n\nAlong with a header (containing display resolution and address) and footer\n(containing CRC).\n\nMy module is designed around a 2d array (or matrix) of rows and columns. One\ncan create this using `FlipDot.matrix`. The matrix is then converted to an\narray of column bytes using `FlipDot.matrixToBytes`. This byte array can\nthen be buffered for the next send (or queued if multiple frames are desired)\nusing `FlipDot.load`. Finally, the buffered data is encoded, packaged and\nsent using `FlipDot.send`. \n\nThis process is largely automated in `FlipDot.writeText`,\n`FlipDot.writeFrames`, `FlipDot.writeParagraph` and `FlipDot.writeMatrix`,\nwith only a call to `FlipDot.send` required.\n\nSee the 'examples/' folder for code usage but broadly:\n\n```javascript\nconst FlipDot = require('flipdot-display');\n\nconst flippy = new FlipDot('/dev/ttyUSB0',5,7,56);\n\nflippy.once('open', function() {\n  flippy.writeText('Hello World');\n  flippy.send();\n});\n```\n\n## Acknowledgements\n\n* [ks156 Python driver](https://github.com/ks156/Hanover_Flipdot) - Explained\n  the _bizare_ protocol expected by the Hanover display and saved a lot of\n  work!\n* [@j_whittington](https://twitter.com/j_whittington) - [JBR\n  Engineering](https://jbrengineering.com) - 2017\n* [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](http://www.gnu.org/licenses/gpl-3.0)\n\n# JSDoc Class\n\n## FlipDot ⇐ \u003ccode\u003eEventEmitter.\u003c/code\u003e\nFlipDot is a Hanover FlipDot display connected via USB RS485\n\n**Kind**: global class  \n**Extends**: \u003ccode\u003eEventEmitter.\u003c/code\u003e  \n**Emits**: \u003ccode\u003eFlipDot#event:sent All data sent\u003c/code\u003e, \u003ccode\u003eFlipDot#event:free Queue\u0026#x27;d data emptied\u003c/code\u003e  \n\n* [FlipDot](#FlipDot) ⇐ \u003ccode\u003eEventEmitter.\u003c/code\u003e\n    * [new FlipDot(port, addr, rows, columns, callback)](#new_FlipDot_new)\n    * [.write(data)](#FlipDot+write)\n    * [.writeDrain(data)](#FlipDot+writeDrain)\n    * [.matrix(rows, col, fill)](#FlipDot+matrix) ⇒ \u003ccode\u003ematrix\u003c/code\u003e\n    * [.matrixToBytes(matrix)](#FlipDot+matrixToBytes) ⇒ \u003ccode\u003earray\u003c/code\u003e\n    * [.writeMatrix(matrix, load)](#FlipDot+writeMatrix) ⇒ \u003ccode\u003earray\u003c/code\u003e\n    * [.writeFrames(frames, refresh)](#FlipDot+writeFrames)\n    * [.writeText(text, fontOpt, offset, invert, load)](#FlipDot+writeText) ⇒ \u003ccode\u003earray\u003c/code\u003e\n    * [.writeParagraph(paragraph, fontOpt, offset, invert, refresh)](#FlipDot+writeParagraph)\n    * [.clear()](#FlipDot+clear)\n    * [.fill(value)](#FlipDot+fill)\n    * [.asciiToByte(chars)](#FlipDot+asciiToByte) ⇒ \u003ccode\u003eint\u003c/code\u003e\n    * [.byteToAscii(byte)](#FlipDot+byteToAscii) ⇒ \u003ccode\u003earray\u003c/code\u003e\n    * [.encode(matrix)](#FlipDot+encode) ⇒ \u003ccode\u003earray\u003c/code\u003e\n    * [.decode(data)](#FlipDot+decode) ⇒ \u003ccode\u003earray\u003c/code\u003e\n    * [.load(data, queue)](#FlipDot+load)\n    * [.send(data, callback)](#FlipDot+send)\n    * [.close(callback)](#FlipDot+close)\n\n\u003ca name=\"new_FlipDot_new\"\u003e\u003c/a\u003e\n\n### new FlipDot(port, addr, rows, columns, callback)\n\n| Param | Type | Description |\n| --- | --- | --- |\n| port | \u003ccode\u003estring\u003c/code\u003e | Serial port of RS485. |\n| addr | \u003ccode\u003eint\u003c/code\u003e | Address of FlipDot display, set with pot internal to display. |\n| rows | \u003ccode\u003eint\u003c/code\u003e | Number of rows on display. |\n| columns | \u003ccode\u003eint\u003c/code\u003e | Number of columns on display. |\n| callback | \u003ccode\u003efunction\u003c/code\u003e | Function to call when port is open. |\n\n\u003ca name=\"FlipDot+write\"\u003e\u003c/a\u003e\n\n### flipDot.write(data)\nWrite data to the serial object.\n\n**Kind**: instance method of [\u003ccode\u003eFlipDot\u003c/code\u003e](#FlipDot)  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| data | \u003ccode\u003ebuffer\u003c/code\u003e | Binary data. |\n\n\u003ca name=\"FlipDot+writeDrain\"\u003e\u003c/a\u003e\n\n### flipDot.writeDrain(data)\nWrite to serial object and wait to drain.\n\n**Kind**: instance method of [\u003ccode\u003eFlipDot\u003c/code\u003e](#FlipDot)  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| data | \u003ccode\u003ebuffer\u003c/code\u003e | Binary data. |\n\n\u003ca name=\"FlipDot+matrix\"\u003e\u003c/a\u003e\n\n### flipDot.matrix(rows, col, fill) ⇒ \u003ccode\u003ematrix\u003c/code\u003e\nReturn matrix (2d array), default size of display (matrix[rows][columns])\n\n**Kind**: instance method of [\u003ccode\u003eFlipDot\u003c/code\u003e](#FlipDot)  \n**Returns**: \u003ccode\u003ematrix\u003c/code\u003e - 2d array [rows][col].  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| rows | \u003ccode\u003eint\u003c/code\u003e | Number of rows (default size of display). |\n| col | \u003ccode\u003eint\u003c/code\u003e | Number of columns (default size of display). |\n| fill | \u003ccode\u003eint\u003c/code\u003e | Value to initialise array. |\n\n\u003ca name=\"FlipDot+matrixToBytes\"\u003e\u003c/a\u003e\n\n### flipDot.matrixToBytes(matrix) ⇒ \u003ccode\u003earray\u003c/code\u003e\nConvert matrix to array of bytes, bytes constructed from rows in each column.\n\n**Kind**: instance method of [\u003ccode\u003eFlipDot\u003c/code\u003e](#FlipDot)  \n**Returns**: \u003ccode\u003earray\u003c/code\u003e - Array of column bytes.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| matrix | \u003ccode\u003ematrix\u003c/code\u003e | 2d array returned from `this.matrix`. |\n\n\u003ca name=\"FlipDot+writeMatrix\"\u003e\u003c/a\u003e\n\n### flipDot.writeMatrix(matrix, load) ⇒ \u003ccode\u003earray\u003c/code\u003e\nLoad matrix, ready to send on next call.\n\n**Kind**: instance method of [\u003ccode\u003eFlipDot\u003c/code\u003e](#FlipDot)  \n**Returns**: \u003ccode\u003earray\u003c/code\u003e - Array of column bytes.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| matrix | \u003ccode\u003ematrix\u003c/code\u003e | 2d array returned from `this.matrix`. |\n| load | \u003ccode\u003ebool\u003c/code\u003e | Whether to load the data or just return encoded. |\n\n\u003ca name=\"FlipDot+writeFrames\"\u003e\u003c/a\u003e\n\n### flipDot.writeFrames(frames, refresh)\nQueue data frames to display in order.\n\n**Kind**: instance method of [\u003ccode\u003eFlipDot\u003c/code\u003e](#FlipDot)  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| frames | \u003ccode\u003earray\u003c/code\u003e | Array of display data in byte format. |\n| refresh | \u003ccode\u003eint\u003c/code\u003e | Refresh rate of frames (ms). |\n\n\u003ca name=\"FlipDot+writeText\"\u003e\u003c/a\u003e\n\n### flipDot.writeText(text, fontOpt, offset, invert, load) ⇒ \u003ccode\u003earray\u003c/code\u003e\nWrite text string to display in ascii art format, using _figlet_ module.\n\n**Kind**: instance method of [\u003ccode\u003eFlipDot\u003c/code\u003e](#FlipDot)  \n**Returns**: \u003ccode\u003earray\u003c/code\u003e - Array of column bytes.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| text | \u003ccode\u003estring\u003c/code\u003e | Text to display. |\n| fontOpt | \u003ccode\u003eobject\u003c/code\u003e | figlet options { font: , horizontalLayout: , verticalLayout: }. |\n| offset | \u003ccode\u003earray\u003c/code\u003e | Text offset cordinates [x,y]. |\n| invert | \u003ccode\u003ebool\u003c/code\u003e | Invert text. |\n| load | \u003ccode\u003ebool\u003c/code\u003e | Whether to load for next send or just return encoded data. |\n\n\u003ca name=\"FlipDot+writeParagraph\"\u003e\u003c/a\u003e\n\n### flipDot.writeParagraph(paragraph, fontOpt, offset, invert, refresh)\nWrite lines of text to display in ascii art format, using _figlet_ module. Same inputs as `writeText` but sends each line as a frame.\n\n**Kind**: instance method of [\u003ccode\u003eFlipDot\u003c/code\u003e](#FlipDot)  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| paragraph | \u003ccode\u003estring\u003c/code\u003e | Lines of text to display; '\\n' line break. |\n| fontOpt | \u003ccode\u003eobject\u003c/code\u003e | figlet options { font: , horizontalLayout: , verticalLayout: }. |\n| offset | \u003ccode\u003earray\u003c/code\u003e | Text offset cordinates [x,y]. |\n| invert | \u003ccode\u003ebool\u003c/code\u003e | Invert text. |\n| refresh | \u003ccode\u003eint\u003c/code\u003e | Period to display each frame. |\n\n\u003ca name=\"FlipDot+clear\"\u003e\u003c/a\u003e\n\n### flipDot.clear()\nClear display (write 0x00 and stop queue).\n\n**Kind**: instance method of [\u003ccode\u003eFlipDot\u003c/code\u003e](#FlipDot)  \n\u003ca name=\"FlipDot+fill\"\u003e\u003c/a\u003e\n\n### flipDot.fill(value)\nFill display with value.\n\n**Kind**: instance method of [\u003ccode\u003eFlipDot\u003c/code\u003e](#FlipDot)  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| value | \u003ccode\u003eint\u003c/code\u003e | hex value to fill. |\n\n\u003ca name=\"FlipDot+asciiToByte\"\u003e\u003c/a\u003e\n\n### flipDot.asciiToByte(chars) ⇒ \u003ccode\u003eint\u003c/code\u003e\nConvert Hanover two ascii charactor format hex value to byte.\n\n**Kind**: instance method of [\u003ccode\u003eFlipDot\u003c/code\u003e](#FlipDot)  \n**Returns**: \u003ccode\u003eint\u003c/code\u003e - Byte.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chars | \u003ccode\u003earray\u003c/code\u003e | Chars representing hex value, eg: ['0','F']. |\n\n\u003ca name=\"FlipDot+byteToAscii\"\u003e\u003c/a\u003e\n\n### flipDot.byteToAscii(byte) ⇒ \u003ccode\u003earray\u003c/code\u003e\nConvert byte to two ascii chars representing hex value.\n\n**Kind**: instance method of [\u003ccode\u003eFlipDot\u003c/code\u003e](#FlipDot)  \n**Returns**: \u003ccode\u003earray\u003c/code\u003e - Two ascii chars of hex value.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| byte | \u003ccode\u003eint\u003c/code\u003e | Byte to convert. |\n\n\u003ca name=\"FlipDot+encode\"\u003e\u003c/a\u003e\n\n### flipDot.encode(matrix) ⇒ \u003ccode\u003earray\u003c/code\u003e\nEncode data for Hanover display; the display reads two ascii chars per byte, representing the visual hex representation of the byte - this means the data packet doubles in size.\n\n**Kind**: instance method of [\u003ccode\u003eFlipDot\u003c/code\u003e](#FlipDot)  \n**Returns**: \u003ccode\u003earray\u003c/code\u003e - Hanover encoded data (two ascii chars representing visual form of each byte).  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| matrix | \u003ccode\u003earray\u003c/code\u003e | Array of column bytes. |\n\n**Example**  \n```js\n// returns ['0', '5']\nFlipDot.encode(0x05);\n```\n\u003ca name=\"FlipDot+decode\"\u003e\u003c/a\u003e\n\n### flipDot.decode(data) ⇒ \u003ccode\u003earray\u003c/code\u003e\nDecode Hanover display data (two ascii chars per byte) back to bytes.\n\n**Kind**: instance method of [\u003ccode\u003eFlipDot\u003c/code\u003e](#FlipDot)  \n**Returns**: \u003ccode\u003earray\u003c/code\u003e - Bytes (will be half size of passed).  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| data | \u003ccode\u003earray\u003c/code\u003e | Hanover display data of ascii chars representing visual form of hex byte. |\n\n**Example**  \n```js\n// returns 0x0F\nFlipDot.asciiToBye(['0', 'F']);\n```\n\u003ca name=\"FlipDot+load\"\u003e\u003c/a\u003e\n\n### flipDot.load(data, queue)\nLoad or queue data for next call to `send`. Does the encoding of data.\n\n**Kind**: instance method of [\u003ccode\u003eFlipDot\u003c/code\u003e](#FlipDot)  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| data | \u003ccode\u003earray\u003c/code\u003e | Array of column bytes. |\n| queue | \u003ccode\u003ebool\u003c/code\u003e | Whether to queue or write data. |\n\n\u003ca name=\"FlipDot+send\"\u003e\u003c/a\u003e\n\n### flipDot.send(data, callback)\nSend data to display over RS485 and load next from queue if available. This should be called without parameters after a `write` or `load` function. Will start task to empty queue if queued data, which will pop frames at `this.refresh` period.\n\n**Kind**: instance method of [\u003ccode\u003eFlipDot\u003c/code\u003e](#FlipDot)  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| data | \u003ccode\u003edata\u003c/code\u003e | Optional: data to send. |\n| callback | \u003ccode\u003efunction\u003c/code\u003e | Function to call once data is sent and drained. |\n\n**Example**  \n```js\nFlipDot.writeText('Hello World');\nFlipDot.send();\n```\n\u003ca name=\"FlipDot+close\"\u003e\u003c/a\u003e\n\n### flipDot.close(callback)\nClose the serial port ready to clear object\n\n**Kind**: instance method of [\u003ccode\u003eFlipDot\u003c/code\u003e](#FlipDot)  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| callback | \u003ccode\u003efunction\u003c/code\u003e | to call when port closed |\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftuna-f1sh%2Fnode-flipdot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftuna-f1sh%2Fnode-flipdot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftuna-f1sh%2Fnode-flipdot/lists"}