Kilka tygodni temu kupiłem sobie małą drukarkę termiczną, którą dzięki interfejsowi TTL można bardzo prosto podpiąć do Arduino. Drukarkę kupiłem z myślą o zastosowaniu jej w pewnym fajnym (i póki co tajnym;) projekcie, ale najpierw postanowiłem się nią nieco pobawić, więc zrobiłem sobie drukarkę statusów z Twittera :D
Jak na tak bezużyteczny gadżet, jakim niewątpliwie jest Twitterowa drukarka, części kosztują dosyć dużo. Pamiętajcie jednak, że sporą część moich projektów trzeba traktować raczej jako wskazanie drogi i przykład zastosowania, a nie jak coś, co obowiązkowo każdy z Was powinien sobie zrobić. Tak jest i tym razem :) Ja do zabawy zrobiłem sobie Twitterową drukarkę, ale Ty możesz sobie zrobić coś dużo bardziej pożytecznego :)
Co nam będzie potrzebne?
Do zrobienia Twitterowej drukarki wykorzystałem:
- Arduino UNO
- Ethernet Shield
- Drukarkę termiczną TTL
- Zasilacz 5V z zasilacza ATX (możesz użyć dowolnego zasilacza 5V o wydajności prądowej minimum 2A)
Jak zrobić Twitterową drukarkę?
Sam układ jest banalnie prosty i jego złożenie ogranicza się w zasadzie do podłączenia tylko kilku przewodów. Na początku wpinamy Ethernet Shield w Arduino, a następnie podłączamy drukarkę w ten sposób:
Całe Arduino możemy oczywiście zasilać z tego samego zasilacza.
Program sterujący drukarką
W Twitterowej drukarce wykorzystałem bibliotekę Thermal Printer, którą po ściągnięciu trzeba wypakować i skopiować do folderu /libraries/ w katalogu z Arduino IDE.
Po skopiowaniu biblioteki wystarczy wgrać do Arduino następujący program:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 |
/* Gutenbird demo sketch: monitors one or more Twitter accounts for changes, displaying updates on attached thermal printer. Written by Adafruit Industries. MIT license. REQUIRES ARDUINO IDE 1.0 OR LATER -- Back-porting is not likely to occur, as the code is deeply dependent on the Stream class, etc. Required hardware includes an Ethernet-connected Arduino board such as the Arduino Ethernet or other Arduino-compatible board with an Arduino Ethernet Shield, plus an Adafruit Mini Thermal Receipt printer and all related power supplies and cabling. Resources: http://www.adafruit.com/products/418 Arduino Ethernet http://www.adafruit.com/products/284 FTDI Friend http://www.adafruit.com/products/201 Arduino Uno http://www.adafruit.com/products/201 Ethernet Shield http://www.adafruit.com/products/597 Mini Thermal Receipt Printer http://www.adafruit.com/products/600 Printer starter pack */ #include <SPI.h> #include <Ethernet.h> #include <Thermal.h> #include <SoftwareSerial.h> // Global stuff -------------------------------------------------------------- const int led_pin = 13, // To status LED (hardware PWM pin) // Pin 4 is skipped -- this is the Card Select line for Arduino Ethernet! printer_RX_Pin = 6, // Printer connection: green wire printer_TX_Pin = 5, // Printer connection: yellow wire printer_Ground = 4, // Printer connection: black wire maxTweets = 10; // Limit tweets printed; avoid runaway output const unsigned long // Time limits, expressed in milliseconds: pollingInterval = 25L * 1000L, // Note: Twitter server will allow 150/hr max connectTimeout = 15L * 1000L, // Max time to retry server link responseTimeout = 15L * 1000L; // Max time to wait for data from server Thermal printer(printer_RX_Pin, printer_TX_Pin); byte sleepPos = 0, // Current "sleep throb" table position resultsDepth, // Used in JSON parsing // Ethernet MAC address is found on sticker on Ethernet shield or board: mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x76, 0x09 }; IPAddress ip(192,168,0,118); // Fallback address -- code will try DHCP first EthernetClient client; char *serverName = "search.twitter.com", // queryString can be any valid Twitter API search string, including // boolean operators. See https://dev.twitter.com/docs/using-search // for options and syntax. Funny characters do NOT need to be URL // encoded here -- the sketch takes care of that. *queryString = "majsterkowo", lastId[21], // 18446744073709551615\0 (64-bit maxint as string) timeStamp[32], // WWW, DD MMM YYYY HH:MM:SS +XXXX\0 fromUser[16], // Max username length (15) + \0 msgText[141], // Max tweet length (140) + \0 name[11], // Temp space for name:value parsing value[141]; // Temp space for name:value parsing PROGMEM byte sleepTab[] = { // "Sleep throb" brightness table (reverse for second half) 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 3, 4, 5, 6, 8, 10, 13, 15, 19, 22, 26, 31, 36, 41, 47, 54, 61, 68, 76, 84, 92, 101, 110, 120, 129, 139, 148, 158, 167, 177, 186, 194, 203, 211, 218, 225, 232, 237, 242, 246, 250, 252, 254, 255 }; // Function prototypes ------------------------------------------------------- boolean jsonParse(int, byte), readString(char *, int); int unidecode(byte), timedRead(void); // --------------------------------------------------------------------------- void setup() { // Set up LED "sleep throb" ASAP, using Timer1 interrupt: TCCR1A = _BV(WGM11); // Mode 14 (fast PWM), 64:1 prescale, OC1A off TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS11) | _BV(CS10); ICR1 = 8333; // ~30 Hz between sleep throb updates TIMSK1 |= _BV(TOIE1); // Enable Timer1 interrupt sei(); // Enable global interrupts Serial.begin(57600); pinMode(printer_Ground, OUTPUT); digitalWrite(printer_Ground, LOW); // Just a reference ground, not power printer.begin(); printer.sleep(); // Initialize Ethernet connection. Request dynamic // IP address, fall back on fixed IP if that fails: Serial.print("Initializing Ethernet..."); if(Ethernet.begin(mac)) { Serial.println("OK"); } else { Serial.print("\r\nno DHCP response, using static IP address."); Ethernet.begin(mac, ip); } // Clear all string data memset(lastId , 0, sizeof(lastId)); memset(timeStamp, 0, sizeof(timeStamp)); memset(fromUser , 0, sizeof(fromUser)); memset(msgText , 0, sizeof(msgText)); memset(name , 0, sizeof(name)); memset(value , 0, sizeof(value)); } // --------------------------------------------------------------------------- void loop() { unsigned long startTime, t; int i; char c; startTime = millis(); // Disable Timer1 interrupt during network access, else there's trouble. // Just show LED at steady 100% while working. :T TIMSK1 &= ~_BV(TOIE1); analogWrite(led_pin, 255); // Attempt server connection, with timeout... Serial.print("Connecting to server..."); while((client.connect(serverName, 80) == false) && ((millis() - startTime) < connectTimeout)); if(client.connected()) { // Success! Serial.print("OK\r\nIssuing HTTP request..."); // URL-encode queryString to client stream: client.print("GET /search.json?q="); for(i=0; c=queryString[i]; i++) { if(((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || ((c >= '0') && (c <= '9')) || (c == '-') || (c == '_') || (c == '.') || (c == '~')) { // Unreserved char: output directly client.write(c); } else { // Reserved/other: percent encode client.write('%'); client.print(c, HEX); } } client.print("&result_type=recent&include_entities=false&rpp="); if(lastId[0]) { client.print(maxTweets); // Limit to avoid runaway printing client.print("&since_id="); // Display tweets since prior query client.print(lastId); } else { client.print('1'); // First run; show single latest tweet } client.print(" HTTP/1.1\r\nHost: "); client.println(serverName); client.println("Connection: close\r\n"); Serial.print("OK\r\nAwaiting results (if any)..."); t = millis(); while((!client.available()) && ((millis() - t) < responseTimeout)); if(client.available()) { // Response received? // Could add HTTP response header parsing here (400, etc.) if(client.find("\r\n\r\n")) { // Skip HTTP response header Serial.println("OK\r\nProcessing results..."); resultsDepth = 0; jsonParse(0, 0); } else Serial.println("response not recognized."); } else Serial.println("connection timed out."); client.stop(); } else { // Couldn't contact server Serial.println("failed"); } // Sometimes network access & printing occurrs so quickly, the steady-on // LED wouldn't even be apparent, instead resembling a discontinuity in // the otherwise smooth sleep throb. Keep it on at least 4 seconds. t = millis() - startTime; if(t < 4000L) delay(4000L - t); // Pause between queries, factoring in time already spent on network // access, parsing, printing and LED pause above. t = millis() - startTime; if(t < pollingInterval) { Serial.print("Pausing..."); sleepPos = sizeof(sleepTab); // Resume following brightest position TIMSK1 |= _BV(TOIE1); // Re-enable Timer1 interrupt for sleep throb delay(pollingInterval - t); Serial.println("done"); } } // --------------------------------------------------------------------------- boolean jsonParse(int depth, byte endChar) { int c, i; boolean readName = true; for(;;) { while(isspace(c = timedRead())); // Scan past whitespace if(c < 0) return false; // Timeout if(c == endChar) return true; // EOD if(c == '{') { // Object follows if(!jsonParse(depth + 1, '}')) return false; if(!depth) return true; // End of file if(depth == resultsDepth) { // End of object in results list // Output to printer printer.wake(); printer.inverseOn(); printer.println(" "); printer.print(fromUser); printer.println(" "); printer.inverseOff(); printer.println(msgText); printer.feed(3); printer.sleep(); // Dump to serial console as well Serial.print("User: "); Serial.println(fromUser); Serial.print("Text: "); Serial.println(msgText); Serial.print("Time: "); Serial.println(timeStamp); // Clear strings for next object timeStamp[0] = fromUser[0] = msgText[0] = 0; } } else if(c == '[') { // Array follows if((!resultsDepth) && (!strcasecmp(name, "results"))) resultsDepth = depth + 1; if(!jsonParse(depth + 1,']')) return false; } else if(c == '"') { // String follows if(readName) { // Name-reading mode if(!readString(name, sizeof(name)-1)) return false; } else { // Value-reading mode if(!readString(value, sizeof(value)-1)) return false; // Process name and value strings: if (!strcasecmp(name, "max_id_str")) { strncpy(lastId, value, sizeof(lastId)-1); } else if(!strcasecmp(name, "created_at")) { strncpy(timeStamp, value, sizeof(timeStamp)-1); } else if(!strcasecmp(name, "from_user")) { strncpy(fromUser, value, sizeof(fromUser)-1); } else if(!strcasecmp(name, "text")) { strncpy(msgText, value, sizeof(msgText)-1); } } } else if(c == ':') { // Separator between name:value readName = false; // Now in value-reading mode value[0] = 0; // Clear existing value data } else if(c == ',') { // Separator between name:value pairs. readName = true; // Now in name-reading mode name[0] = 0; // Clear existing name data } // Else true/false/null or a number follows. These values aren't // used or expected by this program, so just ignore...either a comma // or endChar will come along eventually, these are handled above. } } // --------------------------------------------------------------------------- // Read string from client stream into destination buffer, up to a maximum // requested length. Buffer should be at least 1 byte larger than this to // accommodate NUL terminator. Opening quote is assumed already read, // closing quote will be discarded, and stream will be positioned // immediately following the closing quote (regardless whether max length // is reached -- excess chars are discarded). Returns true on success // (including zero-length string), false on timeout/read error. boolean readString(char *dest, int maxLen) { int c, len = 0; while((c = timedRead()) != '\"') { // Read until closing quote if(c == '\\') { // Escaped char follows c = timedRead(); // Read it // Certain escaped values are for cursor control -- // there might be more suitable printer codes for each. if (c == 'b') c = '\b'; // Backspace else if(c == 'f') c = '\f'; // Form feed else if(c == 'n') c = '\n'; // Newline else if(c == 'r') c = '\r'; // Carriage return else if(c == 't') c = '\t'; // Tab else if(c == 'u') c = unidecode(4); else if(c == 'U') c = unidecode(8); // else c is unaltered -- an escaped char such as \ or " } // else c is a normal unescaped char if(c < 0) return false; // Timeout // In order to properly position the client stream at the end of // the string, characters are read to the end quote, even if the max // string length is reached...the extra chars are simply discarded. if(len < maxLen) dest[len++] = c; } dest[len] = 0; return true; // Success (even if empty string) } // --------------------------------------------------------------------------- // Read a given number of hexadecimal characters from client stream, // representing a Unicode symbol. Return -1 on error, else return nearest // equivalent glyph in printer's charset. (See notes below -- for now, // always returns '-' or -1.) int unidecode(byte len) { int c, v, result = 0; while(len--) { if((c = timedRead()) < 0) return -1; // Stream timeout if ((c >= '0') && (c <= '9')) v = c - '0'; else if((c >= 'A') && (c <= 'F')) v = 10 + c - 'A'; else if((c >= 'a') && (c <= 'f')) v = 10 + c - 'a'; else return '-'; // garbage result = (result << 4) | v; } // To do: some Unicode symbols may have equivalents in the printer's // native character set. Remap any such result values to corresponding // printer codes. Until then, all Unicode symbols are returned as '-'. // (This function still serves an interim purpose in skipping a given // number of hex chars while watching for timeouts or malformed input.) return '-'; } // --------------------------------------------------------------------------- // Read from client stream with a 5 second timeout. Although an // essentially identical method already exists in the Stream() class, // it's declared private there...so this is a local copy. int timedRead(void) { int c; unsigned long start = millis(); while((!client.available()) && ((millis() - start) < 5000L)); return client.read(); // -1 on timeout } // --------------------------------------------------------------------------- // Timer1 interrupt handler for sleep throb ISR(TIMER1_OVF_vect, ISR_NOBLOCK) { // Sine table contains only first half...reflect for second half... analogWrite(led_pin, pgm_read_byte(&sleepTab[ (sleepPos >= sizeof(sleepTab)) ? ((sizeof(sleepTab) - 1) * 2 - sleepPos) : sleepPos])); if(++sleepPos >= ((sizeof(sleepTab) - 1) * 2)) sleepPos = 0; // Roll over TIFR1 |= TOV1; // Clear Timer1 interrupt flag } |
Program nie jest mój (znalazłem go w sieci) i prawdę mówiąc pewnej jego części do końca nie rozumiem, więc nawet nie będę próbował go omawiać ;) Program ma pododawane ładne komentarze, więc dociekliwi mogą go sobie przeanalizować :)
Co robi powyższy program? Co 25 sekund odpytuje serwery Twittera o statusy, w których występuje słowo “majsterkowo”. Jeżeli pojawią się nowe tweety, są od razu drukowane. I to w sumie cała filozofia :)
Z rzeczy najważniejszych:
- w linii 38 możemy sobie ustawić, jak często mają być pobierane nowe Tweety
- w linii 58 ustawiamy słowo, które ma być wyłapywane w statusach
- w liniach od 219 do 227 jest to, co leci do drukarki
- drukować możemy także godzinę wysłania statusu – siedzi ona w zmiennej timeStamp
Drukujemy Tweety!
Po włączeniu zasilania i podłączeniu kabla od internetu wszystko powinno już działać. A działa to mniej więcej tak:
Trochę o kosztach druku
Kilka osób pytało mnie, jak droga jest eksploatacja tej drukarki. Otóż jest ona bardzo tania w użyciu. Powiedziałbym nawet, że śmiesznie tania ;)
Kilka dni temu powiedziałem swoim znajomym o tym, że stojąca u mnie w warsztacie drukarka będzie drukowała ich wiadomości. Ustawiłem im nawet kamerkę i zrobiłem stream, żeby mogli sobie oglądać, jak ich wiadomości wychodzą z drukarki :D
Przez kilka godzin znajomych drukarka wydrukowała około 100 statusów zużywając na to ~4 metry papieru. Jedna rolka papieru o szerokości 57mm i długości 20m (takie wchodzą do tej drukarki) kosztuje 1zł, więc wydrukowanie tych 100 tweetów kosztowało jakieś… 20gr :)
Stream na żywo!
Jeżeli chcecie sprawdzić, czy to rzeczywiście działa, to pod tym adresem znajdziecie stream z kamerki umieszczonej przed moją drukarką: https://new.livestream.com/accounts/1974731/events/1915177.
Wystarczy, że tweetniecie status zawierający słowo majsterkowo (a także @majsterkowo i #majsterkowo), a po chwili zostanie on u mnie wydrukowany :D
W tym miejscu chciałbym też podziękować Tomkowi z zenbox.pl za podesłanie swojej starej kamerki :) Ta moja znaleziona kiedyś w chipsach dawała tak kiepski obraz, że nie dało się odczytać żadnego statusu. Teraz jest już o niebo lepiej, chociaż nie obyło się bez umieszczenia lupy między kamerką a drukarką :D
Kiedyś jednak będę musiał zainwestować w jakąś lepszą kamerę, co by nie musieć się tak za każdym razem bawić ;)
Stream będzie dostępny przez kilka najbliższych dni. Najprawdopodobniej będę go jedynie wyłączać na noc (drukarka cały czas jest doświetlana lampką, przy której ciężko by się spało;)
A tak odbiegając troszeczkę od tematu Twittera – macie jakieś fajne pomysły, do czego jeszcze można by wykorzystać taką drukarkę?
Projekt zacny – już gratulowałem realizacji, ale umieść może stream gdzieś gdzie nie będzie wymagane posiadanie i zakładanie konta aby zerknąć na stream na żywo z drukarki.
Próbowałem robić stream w różnych serwisach i tutaj udało się uzyskać najlepszą jakość i najmniejsze opóźnienia :)
Oglądnąłbym ale nie chce mi się zakładać konta. Wierzę na słowo, że działa xD
Łukaszu, a próbowałeś może justin.tv? Nigdy nie korzystałem i nie używałem, ale wiem że ludzie nawet TV streamują tam i strumienie z gameplayami więc jakość powinna być ok, a nie ma przymusu rejestracji aby oglądać – o ile wiem. Sprawdź również może twitch.tv – co prawda to serwis do streamowania gier, ale może się nie obrażą gdy dorzucisz swoją drukarkę – w końcu można powiedzieć że
twój projekt to rodzaj interaktywnej gry z czytelnikami :)
Popróbuję jeszcze w nocy :)
Próbowałeś streamowania bezpośrednio z VLC? Potrzebne by było jedynie przekierowanie portów.
Próbowałem jakiś czas temu przy okazji innego projektu. Niestety przy moim łączu okazało się to bardzo kiepskim pomysłem ;)
Szkoda. Czekam na email żeby się zarejestrować i mam nadzieję, że przyjdzie.
Ze 2 miesiące temu próbowałem zarejestrować się na pewnej stronie wymiany książek (bez nazwisk :D ) na 2 różne adresy email i do tej pory nie otrzymałem linka aktywacyjnego.
Jak masz w przeglądarce dodatek Stylish, to wystarczy dodać dla tamtej strony:
#fancybox-overlay, #fancybox-content {display: none !important;}
Lub doraźnie można też ręcznie usunąć te dwa divy klikając prawym na stronie i wybierając “Zbadaj element” (tak jest w Chromie – w innych przeglądarkach podobnie;)
Jeśli masz podgląd na wydrukowane tweety to.. już sobie poradziłem AdBlockiem :D
Musiało CI się bardzo nudzić, że na coś takiego wpadłeś. Jednak gratuluję pomysłu ;)
Przecież znalazł ten pomysł w sieci, czytaj ze zrozumieniem.
Genialne w swojej prostocie ;P Ale co Ty chcesz z tą drukarką jeszcze zrobić to nie mam pojęcia ;P Ściągi by fajne wychodziły ;P wydruki na płytki drukowane ;P Jak ethernet to może nie tylko Tweet’y, a jakieś kanały RSS ;P
A tak na marginesie to pamiętaj że paragony fiskalne trzeba przez 5 lat trzymać ;p ;p ;p
Fajna ta drukareczka :) Tylko troszkę droga. Wchodzą do tego takie same rolki jak do kas fiskalnych? Co do pomysłu wykorzystania to myślę że doceni ten projekt jakaś restauracja odbierająca zamówienia przez internet :D
Można by też drukować sobie jakieś statystyki temperatury z termometru :)
Kurcze spodobała mi się ta drukarka :) Jakby kosztowała 100-120zł. to bym kupił ale za 199zł. to trochę za drogo.
Nic nie stoi na przeszkodzie, żebyś ją sobie kupił za 100zł. Widziałeś: https://majsterkowo.pl/dla-majsterkowiczow-zakupy-w-nettigo-za-pol-ceny/ ? ;)
Czyli jak dopiszę do mojego artykułu VU Metra ten moduł mikrofonu z nettigo to będę się kwalifikował do zniżki? :D
Liczyć się będą raczej tylko nowe posty :)
Wygląda mi to na reklamę nettigo… widać idea bloga zmierza ku pieniądzowi…
Jak mi powiesz za co mam sobie kupić pieczywo na śniadanie, zapłacić rachunki (w tym te za hosting i domenę), a także kupować materiały do kolejnych projektów, to z chęcią reklamy wyrzucę :)
A jeżeli chodzi o samo Nettigo, to w chwili obecnej jest w pewnym sensie partnerem Majsterkowa. Chociaż ja kompletnie nic z tego nie mam, bo cała nasza współpraca polega obecnie na tym, że to WY możecie robić tam zakupy za połowę ceny: https://majsterkowo.pl/dla-majsterkowiczow-zakupy-w-nettigo-za-pol-ceny/
Ale pomarudzić trzeba, no nie? ;)
No niestety… Łukaszu – jak śmiesz zarabiać na tym co robisz – oddaj moje pieniędze!!!
Przecież powinieneś miłością do majsterkowania płacić za prąd, pasją za internet i domenę, a chęcią blogowania za mieszkanie, chleb i domenę.
Zacny punkt widzenia… oj jaki ten zespół mały i z kiepskimi instrumentami i mało znany… mija pół roku … ale sprzedajne psy – puszczają ich w radio, sprzedali się, komercha.
Widać z blogerami jest tak samo. Bloger ma przymierać głodem i odrzucać wszelkie sytuacje które mogą doprowadzić do zbrukania się jakimkolwiek dochodem.
Uniosłem się … przepraszam za off-top.
Przypomniał mi się kawał, ze przyszła do lekarza kobieta z czarnym brzuchem i jak lekarz zapytał się czemu tak, odpowiedziała że płaciła za węgiel ;-).
Nie jęcz. Nie zazdrość. Bierz się do roboty. Stwórz lepszy serwis, konkurencję dla majsterkowa. Pełną interesującego materiału. Poświęć swój kawałek życia, wiedzy, środków na stworzenie czegoś lepszego, lepszego dla hobbystów, z tekstami wysokiej jakości, z konkursami (z własnej kieszeni! nie próbuj kombinowania ze sponsorami). I niech cię ręka boska broni przed niecnymi próbami uzyskania z tegoż serwisu “rzek” pieniędzy z niego płynących :> Chętnie popatrzę na taką inicjatywę.
@Tajniak: o zenboxie który zasponsorował kamerkę też nie zapomnij. Nie mniej jednak za pracę kasa się należy.
Fajnie by było to podłączyć pod terminal w linuxie ;]
To by było akurat jeszcze prostsze do zrobienia. :D
Pomysł wbrew pozorom nie jest taki bezużyteczny, być może w przypadku podpięcia drukarki do Twittera wydaje się bezcelowy, ale taka drukarka miała by dobre zastosowanie, np gdyby została podpięta pod stronę internetowa baru czy restauracji, następnie klient dokonywałby zamówienia potraw i podawał adres, a drukarka wydrukowałaby zamówienie, w podobne terminale wyposaża swoich współpracowników znany portal zamówień jedzenia na wynos, warto skomercjalizować projekt
Zastanawiam się czy można w taki sam sposób podłączyć drukarkę hp deskjet f2280. Ona jest na USB więc też wykorzystuje RX i TX.