{"id":26665404,"url":"https://github.com/elsehow/sap","last_synced_at":"2025-03-25T17:37:07.262Z","repository":{"id":76067906,"uuid":"51562961","full_name":"elsehow/sap","owner":"elsehow","description":"super automous printer","archived":false,"fork":false,"pushed_at":"2016-02-20T19:32:38.000Z","size":25,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-04-15T07:13:50.748Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/elsehow.png","metadata":{"files":{"readme":"README.org","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-02-12T02:34:36.000Z","updated_at":"2024-04-15T07:13:50.749Z","dependencies_parsed_at":"2023-05-05T16:31:39.966Z","dependency_job_id":null,"html_url":"https://github.com/elsehow/sap","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elsehow%2Fsap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elsehow%2Fsap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elsehow%2Fsap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elsehow%2Fsap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elsehow","download_url":"https://codeload.github.com/elsehow/sap/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245511392,"owners_count":20627382,"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":[],"created_at":"2025-03-25T17:37:06.781Z","updated_at":"2025-03-25T17:37:07.255Z","avatar_url":"https://github.com/elsehow.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"* sap\n\nSuper Automous Printer\n\nan api for [[https://learn.adafruit.com/pi-thermal-printer/][adafruit's IoT printer]].\n\n* Setup\n** Raspberry Pi setup\n\nLet's assume you've already assembled the printer physically, and configured it to be accesisble wirelessly over SSH.\n\nNow, we'll ssh into our server and follow the setup instructions, heavily inspired by [[https://learn.adafruit.com/pi-thermal-printer/pi-setup-part-2][the adafruit tutorial]], but including a few additions to make the api server run.\n\n#+BEGIN_SRC shell \n#!/bin/bash\n\n# install requisite software\ncurl -sLS https://apt.adafruit.com/add | sudo bash # add adafruit repos\nsudo apt-get update\nsudo apt-get install node # install node\n\n# install thermal printer code\nsudo apt-get install git\ngit clone https://github.com/elsehow/sap\ngit checkout stable\ncd sap\nnpm install\n#+END_SRC\n\nNow, =sudo nano /boot/cmdline.txt= and change the contents to:\n\n#+BEGIN_SRC bash\ndwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait\n#+END_SRC\n\nNow, =sudo nano /etc/inittab= and comment out the last line. After you're done, the last line should read:\n\n#+BEGIN_SRC bash\n# T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100\n#+END_SRC\n\nHooray! Now you can configure and run your print server. \n\n** Server setup\n\nNow, in ~/sap/, write a file called =config.js= to store your secret API key.\n\n#+BEGIN_SRC js \nmodule.exports = 'my-secret-key'\n#+END_SRC\n\nMake sure your API key is unguessable. Anyone who has it will be able to print stuff over your printer!\n\nNow, just =npm start= to start the server as a daemon using [[http://npmjs.com/package/forever][forever]].\n\n#+BEGIN_SRC shell\nnpm start\n#+END_SRC\n\nYou can disconnect from your ssh session, now.\n\n(If you ever want to stop your server, just ssh in again and do =npm stop= in ~/sap).\n\n* Usage\n** Your first print\n\nThere is a simple example client, in =example-client/client.js=.\n\nIt will take strings to print via the command line\n\nTo install it\n\n#+BEGIN_SRC shell\ncd example-client\nnpm install\nnpm link\n#+END_SRC\n\nNow you can use it from anywhere with\n\n#+BEGIN_SRC shell\nthermal-print \"hello, my friendly, furry \nfriends\"\n#+END_SRC\n** Printing stuff with POST requests of JSON\n\nWe can use our API by sending JSON-formatted POST requests to indra.webfactional.com/\n\nJSON requests should look like this:\n\n#+BEGIN_SRC js \nvar payload = {\n  type: 'my-secret-printer-key',\n  message: 'hello my furry, lovely friends'\n}\n#+END_SRC\n\nwhere =type= refers to the secret key of the printer. (you set this key in a file called =config.js=, on your printer).\n\n* Code\n\n=server.js= subscribes to an [[https://github.com/berkeley-biosense/indra-server][indra server]] instance. It receives messages by subscribing to events that have a secret API key in the =type= field of the JSON posted to the indra server.\n\nHere, the server will connect to indra.webfactional.com (but any other hostname running an [[https://github.com/berkeley-biosense/indra-server][indra server]] instance will do).\n\nfinally, we have =example-client/client.js=, which shows how to query the api.\n\nto develop, edit the code below, and [[http://orgmode.org/manual/Extracting-source-code.html][use emacs to tangle the file]].\n\n** server.js\n*** package.json\n\nFirst let's setup its =package.json=\n\n#+BEGIN_SRC json :tangle package.json\n{\n  \"name\": \"printer-server\",\n  \"version\": \"2.0.0\",\n  \"description\": \"a websocket server for the adafruit printer\",\n  \"main\": \"server.js\",\n  \"scripts\": {\n    \"start\": \"forever start -a -m 1 -l server.log -o out.log -e err.log server.js\",\n    \"stop\": \"forever stopall\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/elsehow/sap/\"\n  },\n  \"keywords\": [\n    \"iot\"\n  ],\n  \"author\": \"elsehow\",\n  \"license\": \"BSD-2-Clause\",\n  \"dependencies\": {\n    \"kefir\": \"^3.2.0\",\n    \"serialport\": \"^2.0.6\",\n    \"socket.io-client\": \"^1.4.5\",\n    \"thermalprinter\": \"^0.3.8\"\n  },\n  \"devDependencies\": {\n    \"forever\": \"^0.15.1\"\n  }\n}\n#+END_SRC\n*** server.js\n#+BEGIN_SRC js :tangle server.js\nvar socket = require('socket.io-client')('http://indra.webfactional.com')\n  , spawn = require('child_process').spawn\n  , key = require('./config.js')\n  , Kefir = require('kefir')\n  , SerialPort = require('serialport').SerialPort\n  , serialPort = new SerialPort('/dev/ttyAMA0', {baudrate: 19200 })   \n  , Printer = require('thermalprinter');\n\nfunction logError (e) {\n  console.log('--------err--------')\n  console.log(e)\n}\n\n// a stream of printer objects\n// which come through when printer is ready to print\nvar printerS = Kefir.stream(function (e) {\n  serialPort.on('open', function () {\n    var printer = new Printer(serialPort)\n    printer.on('ready', function () {\n      e.emit(printer)\n    })\n  })\n})\n\n// a stream of socket objects \n// which come through when socket connects to server\nvar socketS = Kefir.stream(function (e) {\n  socket.on('connect', function () {\n    e.emit(socket)\n  })\n})\n\n// setup listener that prints on event\nfunction printOnEvent (socket, printer) {\n  socket.on(key, function (msg) {\n    printer.printLine(msg.message).printLine('\\n\\n').print()\n  })\n  return\n}\n\n// log errors\nsocketS.onError(logError)\nprinterS.onError(logError)\n// set up listener when printer and socket are both ready\nsocketS.combine(printerS, printOnEvent).log('connected to server + printer - ready to print')\n\n#+END_SRC\n\n** example-client/client.js \n#+BEGIN_SRC js :tangle example-client/client.js\n#!/usr/bin/env node\nvar argv = process.argv.slice(2)\n  , key = require('../config.js')\n\nvar payload = { \n  type: key,\n  message: argv[0]\n  //message: 'hello my furry, lovely friends'\n}\n\nvar request = require('request-json')\nvar client = request.createClient('http://indra.webfactional.com')\n\n\nclient.post('/', payload, function(err, res, body) {\n  console.log('posted')\n})\n#+END_SRC\n\n**** =example-client/package.json=\n\n#+BEGIN_SRC :tangle example-client/package.json\n\n{\n  \"dependencies\": {\n    \"request-json\": \"^0.5.5\"\n  }\n}\n\n#+END_SRC\n\n* TODO possible todos / improvements\n** TODO configure server to start on boot\n\nNow let's get the server to start up\n\nEdit  =/etc/rc.local=, and add these two lines at the end, before the =exit 0= line.\n\n#+BEGIN_SRC shell\ncd /home/pi/sap\nnpm start\n#+END_SRC\n** TODO richer formatting in the output?\n*** bold, underines...headings...subset of markdown?\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felsehow%2Fsap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felsehow%2Fsap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felsehow%2Fsap/lists"}