Sitemap / Advertise

Introduction

Via Telegram, control thermal printers remotely to print out notes, shopping lists, URLs, payments, product barcodes, and episode release dates.


Tags

Share

Telegram-enabled Thermal Printer w/ Arduino Nano 33 IoT

Advertisement:


read_later

Read Later



read_later

Read Later

Introduction

Via Telegram, control thermal printers remotely to print out notes, shopping lists, URLs, payments, product barcodes, and episode release dates.

Tags

Share





Advertisement

Advertisement




    Components :
  • [1]Arduino Nano 33 IoT
  • [1]Tiny (Embedded) Thermal Printer
  • [1]MB102 Power Supply Module
  • [1]External Battery
  • [1]Mini Breadboard
  • [1]Jumper Wires

Description

Even though we do not need handwriting or typing nowadays for taking notes or setting appointment reminders thanks to umpteen web and mobile applications, I am still fond of writing down my records on paper like in the old days :) Thus, I decided to create this project, which allows me to benefit from the advantages of an application while taking my notes and reminders on paper.

Instead of programming a web and mobile application from scratch to send commands to my thermal printer, I wanted to use Telegram, a cross-platform cloud-based messaging service compatible with iOS and Android. In Telegram, it is effortless to create bots with a command list unalike any other messaging applications, which are special accounts that do not require an additional phone number to set up. IoT Thermal Printer, Telegram bot I created for this project, let me print records in six different categories I need frequently:

To fetch commands transferred by IoT Thermal Printer, I developed an outgoing webhook for the Telegram bot, which interprets and replies commands or texts when updated by the Telegram Bot API.

Then, to receive commands from the webhook and print out records with graphics (bitmaps) for each category mentioned above, I used an Arduino Nano 33 IoT and a tiny (embedded) thermal printer.

Huge thanks to DFRobot for sponsoring this project.

Sponsored products by DFRobot:

⭐ Embedded Thermal Printer - USB - TTL Serial | Inspect

project-image
Figure - 56.1


project-image
Figure - 56.2


project-image
Figure - 56.3

Step 1: Building a bot for Telegram with BotFather

BotFather is a Telegram bot that lets us create and manage bots on Telegram without any coding required.

⭐ First of all, open BotFather on Telegram and enter /start to view the available command list and manuals.

project-image
Figure - 56.4

⭐ Use the /newbot command to create a new bot. Enter the name of your bot when BotFather asks you for a name. It is displayed in contact details and elsewhere.

thermal printer

⭐ Then, enter the username of your bot. Usernames are 5-32 characters long and are case insensitive, but may only include Latin characters, numbers, and underscores. They must end in 'bot', e.g. 'tetris_bot' or 'TetrisBot'.

thermal_printer_bot

⭐ After these steps, BotFather generates an authorization token for your new bot. The authorization token is a string along the lines of 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11 that is required to authorize the bot and send requests to the Telegram Bot API. Keep your token secure and store it safely.

project-image
Figure - 56.5

⭐ If you want, you can change your bot's name afterward by using the /setname command, as did I.

IoT Thermal Printer

project-image
Figure - 56.6

⭐ Also, you can change your bot's profile picture by using the /setuserpic command.

project-image
Figure - 56.7

⭐ Finally, enter the /setcommands command to create the list of commands supported by your bot. Users will see these commands as suggestions when they type / in the chat with your bot.

⭐ The command list I created for my Telegram bot (IoT Thermal Printer):

project-image
Figure - 56.8

Step 2: Developing a webhook to get updates from the Telegram Bot API in PHP

I developed this webhook, named Telegram_Thermal_Printer_Bot, in PHP to get updates from my bot (IoT Thermal Printer) via the Telegram Bot API. You can download it below - Telegram_Thermal_Printer_Bot.zip.

The webhook has two parts:

I will talk about the results.php in the following steps.

First of all, I created a class named thermal_printer to define the database settings and functions to send texts and pictures as replies to the Telegram bot when the webhook receives updates.

⭐ In the __init__ function, the class requires four parameters to execute functions:

⭐ In the send_message function, the webhook sends the given text to the bot via the Telegram Bot API by using its authorization token.

Syntax: https://api.telegram.org/bot<token>/sendMessage?chat_id=<update_chat_id>&text=<string>

⭐ In the send_photo function, the webhook sends the given picture to the bot via the Telegram Bot API by using its authorization token.

Syntax: https://api.telegram.org/bot<token>/sendPhoto?chat_id=<update_chat_id>&photo=<link>&caption=<string>

⭐ In the database_update function, the webhook saves the data transferred from the bot as command and content to the given database table.


// Define the themal_printer class and functions:
class thermal_printer {
	public $token, $web_path, $conn, $table;
	
	public function __init__($token, $web_path, $conn, $table){
		$this->token = $token;
		$this->web_path = $web_path.$token;
		$this->conn = $conn;
		$this->table = $table;
	}
	
	public function send_message($id, $string){
		$new_message = $this->web_path."/sendMessage?chat_id=".$id."&text=".urlencode($string);
		file_get_contents($new_message);
	}
	
	public function send_photo($id, $photo, $caption){
	    $new_photo = $this->web_path."/sendPhoto?chat_id=".$id."&photo=".$photo."&caption=".$caption;
	    file_get_contents($new_photo);
	}
	
	public function database_update($command, $content){
		$sql = "UPDATE `$this->table` SET `command`='$command', `content`='$content', `status`='ready' LIMIT 1";
		mysqli_query($this->conn, $sql);
	}
}

⭐ Create the printer object and define the required settings.


$printer = new thermal_printer();
$printer->__init__("123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11", "https://api.telegram.org/bot", $conn, $table_name);

⭐ Get updates from the Telegram Bot API.


$updates = json_decode(file_get_contents('php://input'), TRUE); 

⭐ If the webhook receives data from the Telegram Bot API, get the chat ID and message.

⭐ Depending on the type of the message - photo, video, document, and text - reply to the chat with the given ID.

⭐ Using the strpos function, detect whether one of the commands with content data is sent.

⭐ If so, split the content from the command by using the explode function.

⭐ In the bot, you should leave a blank space before entering the text (content) you want to print with thermal printers for these commands:

⭐ Finally, save the transferred command and content to the database table and send the content as the reply to the bot.

⭐ For other commands, reply with the predefined responses:


if($updates['update_id']){
	$chat_id =   $updates['message']['chat']['id'];
	$message = $updates['message']['text'];
    
	if($updates["message"]["photo"]){
		$printer->send_message($chat_id, "Thank you for sending me a photo but I cannot process it yet 🎞");
	}else if($updates["message"]["video"]){
		$printer->send_message($chat_id, "Thank you for sending me a video but I cannot process it yet  📹");
	}else if($updates["message"]["document"]){
		$printer->send_message($chat_id, "Thank you for sending me a file but I cannot process it yet  📜");
	}else{
		if(strpos($message, "/print_notes") !== FALSE){
			$command = "_note";
			$content = explode(" ", $message, 2)[1];
			$printer->database_update($command, $content);
			$printer->send_message($chat_id, "Printed: ".$content);
		}
		if(strpos($message, "/print_shopping_list") !== FALSE){
			$command = "shopping";
			$content = explode(" ", $message, 2)[1];
			$printer->database_update($command, $content);
			$printer->send_message($chat_id, "Printed: ".$content);
		}
		if(strpos($message, "/print_url") !== FALSE){
			$command = "url";
			$content = explode(" ", $message, 2)[1];
			$printer->database_update($command, $content);
			$printer->send_message($chat_id, "Printed: ".$content);
		}
		if(strpos($message, "/print_payments") !== FALSE){
			$command = "payment";
			$content = explode(" ", $message, 2)[1];
			$printer->database_update($command, $content);
			$printer->send_message($chat_id, "Printed: ".$content);
		}
		if(strpos($message, "/print_product_barcode") !== FALSE){
			$command = "barcode";
			$content = explode(" ", $message, 2)[1];
			$printer->database_update($command, $content);
			$printer->send_message($chat_id, "Printed: ".$content);
		}
		if(strpos($message, "/print_series") !== FALSE){
			$command = "series";
			$content = explode(" ", $message, 2)[1];
			$printer->database_update($command, $content);
			$printer->send_message($chat_id, "Printed: ".$content);
		}
		
		switch($message){
		  case '/print_home':
		  $printer->database_update("home", "theamplituhedron.com");
		  $printer->send_message($chat_id, "Printed: OK");
		  break;	
		  case '/start':
		  $printer->send_message($chat_id, "Leave a blank space before entering the text you want to print with thermal printers for these commands:\n\n/print_notes text\n/print_shopping_list item1, item2...\n/print_url text\n/print_payments text\n/print_product_barcode text\n/print_series text\n\nEnter /help to view descriptions.");
		  break;			
		  case 'How r u?':
		  $printer->send_message($chat_id, "Thanks for asking.\nData processing is running just fine 😃");
		  break;
		  case '/cover':
		  $printer->send_photo($chat_id, "https://www.theamplituhedron.com/Telegram_Thermal_Printer_Bot/spiderman.jpg", 'Friendly Neighborhood Spider-Man');
	      break;
		  case '/arduino':
		  $printer->send_photo($chat_id, "https://www.theamplituhedron.com/Telegram_Thermal_Printer_Bot/arduino.jpg", 'Arduino Nano 33 IoT Schematics');
	      break;
		  case '/help':
		  $printer->send_message($chat_id, "Leave a blank space before entering the text you want to print with thermal printers for these commands:\n\n/print_notes text\n/print_shopping_list item1, item2...\n/print_url text\n/print_payments text\n/print_product_barcode text\n/print_series text\n\nDescriptions:\n\n/print_home - print all available functions\n/print_notes - send and print a note\n/print_shopping_list - create and print a shopping list\n/print_url - send and print URLs\n/print_payments - define and print payments\n/print_product_barcode - define and print product barcodes\n/print_series - enter and print a new episode date\n/cover - display the given cover picture\n/arduino - display Nano 33 IoT schematics\n/help - functions and instructions");
		  break;	  
	    }
	}
}

project-image
Figure - 56.9


project-image
Figure - 56.10


project-image
Figure - 56.11

⭐ To be able to collate data transferred by the Telegram Bot API, create a database table and insert default variables.

telegramprinter > entries > variables


CREATE TABLE `entries`(
   command varchar(255) PRIMARY KEY NOT NULL,
   content varchar(255) NOT NULL,
   `status` varchar(255) NOT NULL
);

INSERT INTO `entries`(`command`, `content`, `status`) VALUES ('default' , 'default', 'default')

project-image
Figure - 56.12


project-image
Figure - 56.13

Getting updates by making requests to https://api.telegram.org/ requires an SSL connection, so I used my website to host the webhook.

theamplituhedron.com

project-image
Figure - 56.14

However, the Bot API server source code is available at telegram-bot-api. You can run it locally and send the requests to your server instead of https://api.telegram.org.

Furthermore, if you want to use Raspberry Pi and Python instead of PHP, you can use this Python module to get updates from the Telegram Bot API.

Step 2.1: Setting up the webhook to fetch data from the bot

After creating the webhook, I specified the URL of the webhook for my bot (IoT Thermal Printer) by using the setWebhook method to receive incoming updates.

https://api.telegram.org/bot<token>/setWebhook/?url=https://www.theamplituhedron.com/Telegram_Thermal_Printer_Bot

project-image
Figure - 56.15

⭐ After specifying the URL of your webhook, you should see Webhook was set message.

⭐ Then, go to the Telegram bot and enter /start to test whether the webhook is working accurately or not.

project-image
Figure - 56.16


project-image
Figure - 56.17

⭐ Enter /help to view descriptions.

project-image
Figure - 56.18

⭐ To display the supported command list, enter /.

project-image
Figure - 56.19

Step 2.2: Transferring information coming from the bot as results

After taking the steps above, I developed the results.php to send information (command and content) saved in the database table to the Arduino Nano 33 IoT.

⭐ Select the first row in the database table - entries.

⭐ If the status variable set as "ready", the results.php shows command and content variables separated with the percentage sign (%) as the delimiter.

project-image-slide project-image-slide project-image-slide project-image-slide project-image-slide project-image-slide project-image-slide
Slide


⭐ To prevent sending the same information to the Arduino Nano 33 IoT repetitively, the results.php changes the status variable from "ready" to "printed". Then, it displays Already Printed! Waiting new commands...

project-image
Figure - 56.27


$sql = "SELECT * FROM `$table_name` LIMIT 1";
$result = mysqli_query($conn, $sql);
$check = mysqli_num_rows($result);
if($check < 1){
	echo 'No entry found!';
}else{
	if($row = mysqli_fetch_assoc($result)){
		if($row['status'] == "ready"){
			echo "%".$row['command']."%".$row['content']."%";
			$sql_update = "UPDATE `$table_name` SET `status`='printed' LIMIT 1";
			mysqli_query($conn, $sql_update);
		}else if($row['status'] == "printed"){
			echo "Already Printed! Waiting new commands...";
		}
	}
}

project-image
Figure - 56.28

Step 3: Setting up the Arduino Nano 33 IoT

If you are a novice in programming with the Arduino Nano 33 IoT: do not worry, it is simple to use with Arduino IDE. Just download the required drivers - Arduino SAMD Core - as explained here.

project-image
Figure - 56.29

To be able to connect to the WiFi via the Arduino Nano 33 IoT, download the WiFiNINA library from here.

project-image
Figure - 56.30

I used the second serial port (Serial1) on the Arduino Nano 33 IoT to communicate with the tiny (embedded) thermal printer.

Serial Ports on the Arduino Nano 33 IoT:

"The USB connector of the board is directly connected to the USB host pins of the SAMD21. This routing enables you to use the Arduino NANO 33 IoT as a client USB peripheral (acting as a mouse or a keyboard connected to the computer) or as a USB host device so that devices like a mouse, keyboard, or an Android phone can be connected to the Arduino NANO 33 IoT. This port can also be used as a virtual serial port using the Serial object in the Arduino programming language. The RX0 and TX1 pins are a second serial port available as Serial1."

Then, Arduino Nano 33 IoT is ready to execute the project code :)

Step 4: Printing out texts, bitmaps, and barcodes with the tiny thermal printer

To be able to use the tiny thermal printer with the Arduino Nano 33 IoT, download the Adafruit Thermal Printer library.

Built-in functions in the library to print text with different settings:

In Windows, to print bitmaps with the thermal printer:

⭐ Use an image editing program to save your images as 1-bit BMPs - the built-in Paint program will suffice.

You can download the images I used in this project (converted) below - images.zip.

project-image
Figure - 56.31

⭐ Then, install and run LCD Assistant.

project-image
Figure - 56.32

⭐ First, in the “Byte orientation” section of the settings, select “Horizontal” (item A in the image above).

⭐ Second (item B above), you may need to change the Width setting. Because this software (and the thermal printer) handle images in horizontal groups of eight pixels, if the image width is not a multiple of 8, it will be truncated (cropped) to the nearest smaller 8-pixel boundary.

⭐ After converting each image, at the top of the file containing the new table data, change “const unsigned char” to “static const uint8_t PROGMEM” as shown below:

project-image
Figure - 56.33

⭐ Then, output the image by calling printBitmap(width, height, tablename), where width and height are the dimensions of the image in pixels.

To inspect the tutorial for Mac and Linux, click here.

Barcode Printing:

⭐ To print barcodes with different codes - UPC A, UPC E, EAN13, EAN8, CODE39, I25, CODEBAR, CODE93, CODE128, CODE11 and MSI - use the printBarcode("barcodedata", BARCODETYPE) function in the library.

In the Arduino IDE, after completing the steps above:

⭐ Define and initiate the thermal printer.


Adafruit_Thermal printer(&Serial1);

...

// NOTE: SOME PRINTERS NEED 19200 BAUD instead of 9600, check test page.
Serial1.begin(9600);  // Initialize hardware serial
printer.begin();

⭐ Include the converted bitmaps.


#include "note.h"
#include "list.h"
#include "url.h"
#include "payment.h"
#include "product.h"
#include "series.h"
#include "home.h"

⭐ Define functions for each command to print the content transferred from the Telegram bot when requested.

⭐ For each command, start printing with the given command sign (bitmap).


void print_notes(String text){
  printer.printBitmap(80, 80, note_logo);
  printer.boldOn();
  printer.justify('R');
  printer.setSize('L');
  printer.println(F("Note\n"));
  printer.boldOff();
  printer.justify('L');
  printer.setSize('M');
  printer.println(text);
  printer.feed(5);
  printer.setDefault(); // Restore printer to defaults
}

void print_shopping_list(String text){
  printer.printBitmap(80, 80, list_logo);
  printer.boldOn();
  printer.justify('R');
  printer.setSize('L');
  printer.println(F("Shopping"));
  printer.println(F("List\n"));
  printer.boldOff();
  printer.justify('L');
  printer.setSize('S');
  printer.setLineHeight(50);
  printer.println(text);
  printer.setLineHeight();
  printer.feed(5);
  printer.setDefault(); // Restore printer to defaults
}

void print_URL(String text){
  printer.printBitmap(80, 80, url_logo);
  printer.boldOn();
  printer.justify('R');
  printer.setSize('L');
  printer.println(F("URL\n"));
  printer.boldOff();
  printer.justify('L');
  printer.setSize('S');
  printer.println(text);
  printer.feed(5);
  printer.setDefault(); // Restore printer to defaults
}

void print_payments(String text){
  printer.printBitmap(80, 80, payment_logo);
  printer.boldOn();
  printer.justify('R');
  printer.setSize('L');
  printer.println(F("Payment\n"));
  printer.boldOff();
  printer.justify('L');
  printer.setSize('M');
  printer.println(text);
  printer.feed(5);
  printer.setDefault(); // Restore printer to defaults
}

void print_series(String text){
  printer.printBitmap(80, 80, series_logo);
  printer.boldOn();
  printer.justify('R');
  printer.setSize('L');
  printer.println(F("New"));
  printer.println(F("Episode\n"));
  printer.boldOff();
  printer.justify('L');
  printer.setSize('M');
  printer.println(text);
  printer.feed(5);
  printer.setDefault(); // Restore printer to defaults
}

⭐ In the print_product_barcode function, print out the content as a barcode with the CODE 93 code (compressed version of CODE 39).


void print_product_barcode(const char *text){
  printer.printBitmap(80, 80, product_logo);
  printer.boldOn();
  printer.justify('R');
  printer.setSize('L');
  printer.println(F("Product\n"));
  printer.boldOff();
  printer.justify('L');
  // CODE 93: compressed version of CODE 39:
  printer.setBarcodeHeight(30);
  printer.printBarcode(text, CODE93);
  printer.feed(5);
  printer.setDefault(); // Restore printer to defaults
}

project-image
Figure - 56.34

Step 5: Programming the Arduino Nano 33 IoT

⭐ Include the required libraries.

⭐ Define the server and the pathway of the results page of the Telegram webhook.

⭐ Initialize the Ethernet client library.


// Change the server before running the code.
char server[] = "www.theamplituhedron.com";

// Define the pathway of the results page of the Telegram webhook.
String application = "/Telegram_Thermal_Printer_Bot/results.php";

// Initialize the Ethernet client library.
WiFiSSLClient client;

⭐ Check and connect to the WiFi module.

⭐ Connect to the Telegram webhook's results page.


  // Connect to the Telegram webhook's results page on TheAmplituhedron.
  if (client.connect(server, 443)){
    Serial.println("Connected to the results page!"); // If get a connection, report back via serial:
    // Make an HTTP request:
    client.println("GET " + application + " HTTP/1.1");
    client.println("Host: www.theamplituhedron.com");
    client.println("Connection: close");
    client.println();
  }else{
    Serial.println("Connection Error!");
  }

⭐ If there are incoming bytes available, get the response from the Telegram webhook's results page.

⭐ Using the indexOf() function, check whether the Telegram bot (IoT Thermal Printer) sent a new command or not.

⭐ If so, split the response string by the predefined delimiter - the percentage sign (%).

⭐ Glean information as substrings (command and content).

⭐ Print the requested command with the given content.


  // If there are incoming bytes available, get the response from the Telegram webhook's results page.
  String response = "";
  while (client.available()) { char c = client.read(); response += c; }
  if(response != "" && response.indexOf("%") > 0){
    // Split the response string by a pre-defined delimiter in a simple way. '%'(percentage) is defined as the delimiter in this project.
    int delimiter, delimiter_1, delimiter_2;
    delimiter = response.indexOf("%");
    delimiter_1 = response.indexOf("%", delimiter + 1);
    delimiter_2 = response.indexOf("%", delimiter_1 +1);
    // Glean information as substrings.
    String command = response.substring(delimiter + 1, delimiter_1);
    String content = response.substring(delimiter_1 + 1, delimiter_2);
    // Print the requested command with the given content:
    if(command == "_note") print_notes(content);
    if(command == "shopping") print_shopping_list(content);
    if(command == "url") print_URL(content);
    if(command == "payment") print_payments(content);
    if(command == "barcode"){ char converted[sizeof(content)]; content.toCharArray(converted, sizeof(converted)); print_product_barcode(converted); }
    if(command == "series") print_series(content);
    if(command == "home") print_home(content);
  }
  delay(3000); // Wait 3 seconds before connection...
}

⭐ For the print_product_barcode() function to print the given content as a barcode, convert the "content" string to the "converted" char array.


char converted[sizeof(content)]; content.toCharArray(converted, sizeof(converted));

project-image
Figure - 56.35


project-image
Figure - 56.36


project-image
Figure - 56.37


project-image
Figure - 56.38


project-image
Figure - 56.39

⭐ Finally, verify the connection on the serial monitor.

project-image
Figure - 56.40

Connections and Adjustments


// Connections
// Arduino Nano 33 IoT :           
//                                Tiny (Embedded) Thermal Printer
// TX  --------------------------- RX
// RX  --------------------------- TX
// GND --------------------------- GND

I connected the tiny (embedded ) thermal printer to the Arduino Nano 33 IoT via the 5-pin communication cable. Then, to supply the thermal printer, I used a 12V external battery connected to an MB102 Power Supply Module. The higher the voltage, the clearer the printing effect (5~9V).

project-image
Figure - 56.41

I placed the mini breadboard, the Arduino Nano 33 IoT, and the MB102 Power Supply Module to the top of the tiny thermal printer. To the bottom, I fastened the external battery to conclude my design.

project-image
Figure - 56.42


project-image
Figure - 56.43

Modes and Features

📱📜 When the user sends a message including the /print_notes command on the Telegram bot (IoT Thermal Printer), the thermal printer prints out the given text as a note:

/print_notes Meeting at 5 PM.

project-image
Figure - 56.44


project-image
Figure - 56.45


project-image
Figure - 56.46

📱📜 When the user sends a message including the /print_shopping_list command on the Telegram bot, the thermal printer prints out the given text as a shopping list:

📱📜 Add \n to start a new line in the list.

/print_shopping_list 1.Meat and Fish\n2.Bread\n3.Dairy\n4.Eggs\n5.Condiments

project-image
Figure - 56.47


project-image
Figure - 56.48


project-image
Figure - 56.49

📱📜 When the user sends a message including the /print_url command on the Telegram bot, the thermal printer prints out the given text as an URL:

/print_url https://www.hackster.io/kutluhan-aktar

project-image
Figure - 56.50


project-image
Figure - 56.51


project-image
Figure - 56.52


project-image
Figure - 56.53

📱📜 When the user sends a message including the /print_payments command on the Telegram bot, the thermal printer prints out the given text as a payment reminder:

/print_payments $50 on 01/12

project-image
Figure - 56.54


project-image
Figure - 56.55


project-image
Figure - 56.56

📱📜 When the user sends a message including the /print_product_barcode command on the Telegram bot, the thermal printer prints out the given text (Manufacturer Product Number) as a barcode:

/print_product_barcode DFRO503

project-image
Figure - 56.57


project-image
Figure - 56.58


project-image
Figure - 56.59

📱📜 When the user sends a message including the /print_series command on the Telegram bot, the thermal printer prints out the given text as the new episode release date of a series:

/print_series One Piece 01/10/21

project-image
Figure - 56.60


project-image
Figure - 56.61


project-image
Figure - 56.62

📱📜 When the user activates the /print_home command on the Telegram bot, as the home page, the thermal printer prints out all available features with their given command signs (bitmaps):

project-image
Figure - 56.63


project-image
Figure - 56.64


project-image
Figure - 56.65

📱📜 When the user activates the /cover command on the Telegram bot, the webhook replies with the selected cover picture for the bot :)

project-image
Figure - 56.66

📱📜 When the user activates the /arduino command on the Telegram bot, the webhook replies with the Arduino Nano 33 IoT pinout:

project-image
Figure - 56.67

Videos and Conclusion

After completing all steps above, I started to print out all my notes and reminders via Telegram without needing handwriting :)

project-image
Figure - 56.68

Code

Telegram-Enabled-Thermal-Printer.ino

Download



         /////////////////////////////////////////////  
        //     Telegram-Enabled Thermal Printer    //
       //             w/ Nano 33 IoT              //
      //             ---------------             //
     //          (Arduino Nano 33 IoT)          //           
    //             by Kutluhan Aktar           // 
   //                                         //
  /////////////////////////////////////////////

//
// Via Telegram, control thermal printers to print notes, shopping lists, URLs, payments, product barcodes, and episode release dates.
//
// For more information:
// https://www.theamplituhedron.com/projects/Telegram-enabled-Thermal-Printer-with-Arduino-Nano-33-IoT
//
//
// Connections
// Arduino Nano 33 IoT :           
//                                Tiny (Embedded) Thermal Printer
// TX  --------------------------- RX
// RX  --------------------------- TX
// GND --------------------------- GND


// Include the required libraries.
#include <SPI.h>
#include <WiFiNINA.h>
#include "Adafruit_Thermal.h"


char ssid[] = "[_SSID_]";        // your network SSID (name)
char pass[] = "[_PASSWORD_]";    // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;                // your network key Index number (needed only for WEP)

int status = WL_IDLE_STATUS;

// Change the server before running the code.
char server[] = "www.theamplituhedron.com";

// Define the pathway of the results page of the Telegram webhook.
String application = "/Telegram_Thermal_Printer_Bot/results.php";

// Initialize the Ethernet client library.
WiFiSSLClient client;

// Hardware Serial
Adafruit_Thermal printer(&Serial1);     // Pass addr to printer constructor

// Include icons and pictures to be printed.
#include "note.h"
#include "list.h"
#include "url.h"
#include "payment.h"
#include "product.h"
#include "series.h"
#include "home.h"

void setup() {
  // NOTE: SOME PRINTERS NEED 19200 BAUD instead of 9600, check test page.
  Serial1.begin(9600);  // Initialize hardware serial
  printer.begin();      // Init printer (same regardless of serial type)

  // Check for the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) { Serial.println("Communication with WiFi module failed!"); while (true); }
  // Attempt to connect to Wifi network:
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);
    // Wait 10 seconds for connection:
    delay(10000);
  }

  // Verify connection on the serial monitor.
  Serial.println("Connected to WiFi!");
  delay(1000);

  // Print the home page showing available commands and functions:
  // print_home("theamplituhedron.com");
}

void loop() {
  // Connect to the Telegram webhook's results page on TheAmplituhedron.
  if (client.connect(server, 443)){
    Serial.println("Connected to the results page!"); // If get a connection, report back via serial:
    // Make an HTTP request:
    client.println("GET " + application + " HTTP/1.1");
    client.println("Host: www.theamplituhedron.com");
    client.println("Connection: close");
    client.println();
  }else{
    Serial.println("Connection Error!");
  }

  delay(2000); // Wait 2 seconds after connection...
  
  // If there are incoming bytes available, get the response from the Telegram webhook's results page.
  String response = "";
  while (client.available()) { char c = client.read(); response += c; }
  if(response != "" && response.indexOf("%") > 0){
    // Split the response string by a pre-defined delimiter in a simple way. '%'(percentage) is defined as the delimiter in this project.
    int delimiter, delimiter_1, delimiter_2;
    delimiter = response.indexOf("%");
    delimiter_1 = response.indexOf("%", delimiter + 1);
    delimiter_2 = response.indexOf("%", delimiter_1 +1);
    // Glean information as substrings.
    String command = response.substring(delimiter + 1, delimiter_1);
    String content = response.substring(delimiter_1 + 1, delimiter_2);
    // Print the requested command with the given content:
    if(command == "_note") print_notes(content);
    if(command == "shopping") print_shopping_list(content);
    if(command == "url") print_URL(content);
    if(command == "payment") print_payments(content);
    if(command == "barcode"){ char converted[sizeof(content)]; content.toCharArray(converted, sizeof(converted)); print_product_barcode(converted); }
    if(command == "series") print_series(content);
    if(command == "home") print_home(content);
  }
  delay(3000); // Wait 3 seconds before connection...
}

void print_notes(String text){
  printer.printBitmap(80, 80, note_logo);
  printer.boldOn();
  printer.justify('R');
  printer.setSize('L');
  printer.println(F("Note\n"));
  printer.boldOff();
  printer.justify('L');
  printer.setSize('M');
  printer.println(text);
  printer.feed(5);
  printer.setDefault(); // Restore printer to defaults
}

void print_shopping_list(String text){
  printer.printBitmap(80, 80, list_logo);
  printer.boldOn();
  printer.justify('R');
  printer.setSize('L');
  printer.println(F("Shopping"));
  printer.println(F("List\n"));
  printer.boldOff();
  printer.justify('L');
  printer.setSize('S');
  printer.setLineHeight(50);
  printer.println(text);
  printer.setLineHeight();
  printer.feed(5);
  printer.setDefault(); // Restore printer to defaults
}

void print_URL(String text){
  printer.printBitmap(80, 80, url_logo);
  printer.boldOn();
  printer.justify('R');
  printer.setSize('L');
  printer.println(F("URL\n"));
  printer.boldOff();
  printer.justify('L');
  printer.setSize('S');
  printer.println(text);
  printer.feed(5);
  printer.setDefault(); // Restore printer to defaults
}

void print_payments(String text){
  printer.printBitmap(80, 80, payment_logo);
  printer.boldOn();
  printer.justify('R');
  printer.setSize('L');
  printer.println(F("Payment\n"));
  printer.boldOff();
  printer.justify('L');
  printer.setSize('M');
  printer.println(text);
  printer.feed(5);
  printer.setDefault(); // Restore printer to defaults
}

void print_product_barcode(const char *text){
  printer.printBitmap(80, 80, product_logo);
  printer.boldOn();
  printer.justify('R');
  printer.setSize('L');
  printer.println(F("Product\n"));
  printer.boldOff();
  printer.justify('L');
  // CODE 93: compressed version of CODE 39:
  printer.setBarcodeHeight(30);
  printer.printBarcode(text, CODE93);
  printer.feed(5);
  printer.setDefault(); // Restore printer to defaults
}

void print_series(String text){
  printer.printBitmap(80, 80, series_logo);
  printer.boldOn();
  printer.justify('R');
  printer.setSize('L');
  printer.println(F("New"));
  printer.println(F("Episode\n"));
  printer.boldOff();
  printer.justify('L');
  printer.setSize('M');
  printer.println(text);
  printer.feed(5);
  printer.setDefault(); // Restore printer to defaults
}

void print_home(String _server){
  printer.printBitmap(80, 80, home_logo);
  printer.printBitmap(80, 80, home_logo);
  printer.printBitmap(80, 80, home_logo);
  printer.boldOn();
  printer.justify('C');
  printer.setSize('L');
  printer.println(F("Telegram"));
  printer.println(F("Enabled"));
  printer.println(F("Thermal"));
  printer.println(F("Printer\n"));
  printer.justify('L');
  printer.setSize('M');
  printer.println(F("Available"));
  printer.println(F("Printer"));
  printer.println(F("Commands:\n"));
  printer.boldOff();
  printer.setSize('S');
  printer.setLineHeight(50);
  printer.println(F("1) Notes\n"));
  printer.printBitmap(80, 80, note_logo);
  printer.println(F("2) Shopping List\n"));
  printer.printBitmap(80, 80, list_logo);
  printer.println(F("3) URL\n"));
  printer.printBitmap(80, 80, url_logo);
  printer.println(F("4) Payments\n"));
  printer.printBitmap(80, 80, payment_logo);
  printer.println(F("5) Product Barcode\n"));
  printer.printBitmap(80, 80, product_logo);
  printer.println(F("6) Series\n"));
  printer.printBitmap(80, 80, series_logo);
  printer.println(F("7) Home\n"));
  printer.printBitmap(80, 80, home_logo);
  printer.justify('C');
  printer.println(F("Running On:"));
  printer.println(_server);
  printer.setSize('L');
  printer.inverseOn();
  printer.println(F("&&&&&"));
  printer.inverseOff();
  printer.feed(5);
  printer.setDefault(); // Restore printer to defaults
}


index.php (webhook)

Download



<?php

// Define the themal_printer class and functions:
class thermal_printer {
	public $token, $web_path, $conn, $table;
	
	public function __init__($token, $web_path, $conn, $table){
		$this->token = $token;
		$this->web_path = $web_path.$token;
		$this->conn = $conn;
		$this->table = $table;
	}
	
	public function send_message($id, $string){
		$new_message = $this->web_path."/sendMessage?chat_id=".$id."&text=".urlencode($string);
		file_get_contents($new_message);
	}
	
	public function send_photo($id, $photo, $caption){
	    $new_photo = $this->web_path."/sendPhoto?chat_id=".$id."&photo=".$photo."&caption=".$caption;
	    file_get_contents($new_photo);
	}
	
	public function database_update($command, $content){
		$sql = "UPDATE `$this->table` SET `command`='$command', `content`='$content', `status`='ready' LIMIT 1";
		mysqli_query($this->conn, $sql);
	}
}

// Define database and server settings:
$server = "localhost";
$username = "<username>";
$password = "<password>";
$database_name = "telegramprinter";
$table_name = "entries";

$conn = mysqli_connect($server, $username, $password, $database_name);

$printer = new thermal_printer();
$printer->__init__("123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11", "https://api.telegram.org/bot", $conn, $table_name);

// Get updates from the Telegram Bot API.
$updates = json_decode(file_get_contents('php://input'), TRUE); 

// Get commands.
if($updates['update_id']){
	$chat_id =   $updates['message']['chat']['id'];
	$message = $updates['message']['text'];
    
	if($updates["message"]["photo"]){
		$printer->send_message($chat_id, "Thank you for sending me a photo but I cannot process it yet 🎞");
	}else if($updates["message"]["video"]){
		$printer->send_message($chat_id, "Thank you for sending me a video but I cannot process it yet  📹");
	}else if($updates["message"]["document"]){
		$printer->send_message($chat_id, "Thank you for sending me a file but I cannot process it yet  📜");
	}else{
		if(strpos($message, "/print_notes") !== FALSE){
			$command = "_note";
			$content = explode(" ", $message, 2)[1];
			$printer->database_update($command, $content);
			$printer->send_message($chat_id, "Printed: ".$content);
		}
		if(strpos($message, "/print_shopping_list") !== FALSE){
			$command = "shopping";
			$content = explode(" ", $message, 2)[1];
			$printer->database_update($command, $content);
			$printer->send_message($chat_id, "Printed: ".$content);
		}
		if(strpos($message, "/print_url") !== FALSE){
			$command = "url";
			$content = explode(" ", $message, 2)[1];
			$printer->database_update($command, $content);
			$printer->send_message($chat_id, "Printed: ".$content);
		}
		if(strpos($message, "/print_payments") !== FALSE){
			$command = "payment";
			$content = explode(" ", $message, 2)[1];
			$printer->database_update($command, $content);
			$printer->send_message($chat_id, "Printed: ".$content);
		}
		if(strpos($message, "/print_product_barcode") !== FALSE){
			$command = "barcode";
			$content = explode(" ", $message, 2)[1];
			$printer->database_update($command, $content);
			$printer->send_message($chat_id, "Printed: ".$content);
		}
		if(strpos($message, "/print_series") !== FALSE){
			$command = "series";
			$content = explode(" ", $message, 2)[1];
			$printer->database_update($command, $content);
			$printer->send_message($chat_id, "Printed: ".$content);
		}
		
		switch($message){
		  case '/print_home':
		  $printer->database_update("home", "theamplituhedron.com");
		  $printer->send_message($chat_id, "Printed: OK");
		  break;	
		  case '/start':
		  $printer->send_message($chat_id, "Leave a blank space before entering the text you want to print with thermal printers for these commands:\n\n/print_notes text\n/print_shopping_list item1, item2...\n/print_url text\n/print_payments text\n/print_product_barcode text\n/print_series text\n\nEnter /help to view descriptions.");
		  break;			
		  case 'How r u?':
		  $printer->send_message($chat_id, "Thanks for asking.\nData processing is running just fine 😃");
		  break;
		  case '/cover':
		  $printer->send_photo($chat_id, "https://www.theamplituhedron.com/Telegram_Thermal_Printer_Bot/spiderman.jpg", 'Friendly Neighborhood Spider-Man');
	      break;
		  case '/arduino':
		  $printer->send_photo($chat_id, "https://www.theamplituhedron.com/Telegram_Thermal_Printer_Bot/arduino.jpg", 'Arduino Nano 33 IoT Schematics');
	      break;
		  case '/help':
		  $printer->send_message($chat_id, "Leave a blank space before entering the text you want to print with thermal printers for these commands:\n\n/print_notes text\n/print_shopping_list item1, item2...\n/print_url text\n/print_payments text\n/print_product_barcode text\n/print_series text\n\nDescriptions:\n\n/print_home - print all available functions\n/print_notes - send and print a note\n/print_shopping_list - create and print a shopping list\n/print_url - send and print URLs\n/print_payments - define and print payments\n/print_product_barcode - define and print product barcodes\n/print_series - enter and print a new episode date\n/cover - display the given cover picture\n/arduino - display Nano 33 IoT schematics\n/help - functions and instructions");
		  break;	  
	    }
	}
}

?>


results.php

Download



<?php

// Define database and server settings:
$server = "localhost";
$username = "<username>";
$password = "<password>";
$database_name = "telegramprinter";
$table_name = "entries";

$conn = mysqli_connect($server, $username, $password, $database_name);

$sql = "SELECT * FROM `$table_name` LIMIT 1";
$result = mysqli_query($conn, $sql);
$check = mysqli_num_rows($result);
if($check < 1){
	echo 'No entry found!';
}else{
	if($row = mysqli_fetch_assoc($result)){
		if($row['status'] == "ready"){
			echo "%".$row['command']."%".$row['content']."%";
			$sql_update = "UPDATE `$table_name` SET `status`='printed' LIMIT 1";
			mysqli_query($conn, $sql_update);
		}else if($row['status'] == "printed"){
			echo "Already Printed! Waiting new commands...";
		}
	}
}

?>


Schematics

project-image
Schematic - 56.1

Downloads

Telegram_Thermal_Printer_Bot.zip

Download


note.h

Download


list.h

Download


url.h

Download


payment.h

Download


product.h

Download


series.h

Download


home.h

Download


images.zip

Download