I am trying to create a device that can control 3D printers using serial communication. For this, the microcontroller I chose was the ESP32-CAM by AI Thinkers. I connected the ESP32-CAM to the WiFi and used Telegram, to communicate with the ESP. I bought a Y-Connector to split communication and power to the microcontroller. I tested that the data line in this connector is working properly using a pendrive. I connected the ESP to the PC and tested if everything is working properly. When I type and send a phrase in Telegram (example: "M115"). The serial monitor is displaying M115", and when I write "Hi" in the serial monitor, I am getting that in telegram as a response.
All these are working fine between ESP and PC, but when I connect ESP to a 3D printer, I didn't get any response back from the printer. I tried a similar thing using my PC and 3D printer. If I serially write M115, I get firmware information from the printer.
// Telebot.hpp
#pragma once
#include "WCharacter.h"
#include <UniversalTelegramBot.h>
#include <WiFiClientSecure.h>
#include <algorithm>
#include <string>
#include <vector>
#include <cctype>
#define TRANSFER_BAUDRATE 115200
#define A_OK "All OK! Start the transfer."
#define USAGE_INFO_ALL "Hi! \nThis is a bot to interface with you 3D printer. \n\n*Options:*\n*/print* as a caption to the GCODE file to print the file. \n*/command* to enter into command mode."
#define USAGE_INFO_PRINT "No file uploaded.\nUpload the file and type /print as the caption. :*"
#define USAGE_INFO_COMMAND "Welcome to *Command Mode*. \nHere you can communicate with your printer and test your statements.\nYou will stay in this mode until you use one of the following commands:\n*/end* or */exit* or */x*"
#define USAGE_INFO_COMMAD_ERROR "You are in command mode. You will stay in this mode until you use one of the following commands:\n*/end* or */exit* or */x*"
class Telebot {
private:
const String _token {"Don\'t know"};
WiFiClientSecure _client;
UniversalTelegramBot _bot;
public:
Telebot() = delete;
Telebot(const String);
const bool initSD();
telegramMessage* const getNextMsg ();
void handleMsgs();
void handleCommand(const telegramMessage&);
const bool sendMsg(const String&, const String);
const bool sendBusyMsg(const String);
const String get_token() const;
const bool is_connected();
void sPrint_telegramMessage(const telegramMessage&) const ;
};
// Telebot.cpp
#include "Telebot.hpp"
//
String toLowercase(String str) {
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) {
return std::tolower(c);
});
return str;
}
String toUppercase(String str) {
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) {
return std::toupper(c);
});
return str;
}
#ifdef DEBUG
inline void printDebug (const String& msg){
Serial.print("[!] => ");
Serial.println(msg);
}
#endif
// Constructor
Telebot::Telebot(const String token)
: _token{token}, _bot{UniversalTelegramBot(_token, _client)}, _meta{1024}
{
// Add root certificate for api.telegram.org
_client.setCACert(TELEGRAM_CERTIFICATE_ROOT);
// Initialize SD card
initSD();
}
const bool Telebot::initSD(){
if(SD_MMC.begin()){
#ifdef DEBUG
printDebug("Card Mount Successful");
#endif
return true;
}
else {
#ifdef DEBUG
printDebug("Card Mount Failed");
#endif
}
return false;
}
telegramMessage* const Telebot::getNextMsg (){
short n = _bot.getUpdates(_bot.last_message_received + 1);
// if no new messages do nothing
if (!n) return nullptr;
return &_bot.messages[0];
}
// Handle new messages sent by user
void Telebot::handleMsgs(){
short n = _bot.getUpdates(_bot.last_message_received + 1);
// if no new messages do nothing
if (!n) return;
for (short msgIdx = 0; msgIdx < n; msgIdx++){
telegramMessage& tMsg {_bot.messages[msgIdx]};
String Msg = tMsg.text;
#ifdef DEBUG
printDebug(Msg);
#endif
if (toLowercase(Msg) == "/command"){
handleCommand(tMsg);
}
}
}
// Handle /command command
void Telebot::handleCommand(const telegramMessage& tMsg){
sendMsg(tMsg.chat_id, USAGE_INFO_COMMAND);
std::vector<String> endCmds = {"/end", "/exit", "/x"};
const telegramMessage *tM {nullptr};
String cmd {""};
String recvTxt{"Recv: "};
String responce {}, resTxt{};
String prevChatId {};
while (true) {
tM = getNextMsg();
if (tM) {
prevChatId = tM->chat_id;
cmd = tM->text;
recvTxt = "Recv: " + toUppercase(cmd);
sendMsg(prevChatId, recvTxt);
if (std::find(endCmds.begin(), endCmds.end(), toLowerCase(cmd)) != endCmds.end()) break;
if (cmd.startsWith("/"))
sendMsg(tM->chat_id, USAGE_INFO_COMMAD_ERROR);
else
Serial.println(toUppercase(cmd));
}
if (Serial.available()) {
responce = Serial.readStringUntil('\n');
resTxt = "Resp: " + responce;
sendMsg(prevChatId, resTxt);
}
}
#ifdef DEBUG
printDebug("Exiting Command Mode.");
Serial.println("Exiting Command Mode.");
#endif
}
// Helper function to send simple message
const bool Telebot::sendMsg(const String& chatId, const String Msg){
#ifdef DEBUG
printDebug("Sending the info: \n" + Msg);
#endif
return _bot.sendMessage(chatId, Msg, "markdown");
}
const String Telebot::get_token() const{
return _token;
}
When I connect printer to PC and serial print "M115", the printer response is the current firmware info. This I tested using a python code that I wrote. I want the same with ESP32-CAM.
The ESP32-CAM does not have a USB port built-in to program it. For that, I have an FTDI Programmer board attached to the ESP32-CAM, and I have a Y-splitter attached to this board to power the board and communicate with the board. The Y-splitter is not required when it is connected to a PC.
(FYI: I checked the communication line of the Y-splitter with a pen drive and phone. It is working fine in data transfer.)
I think if the board works with PC it should work with the printer because both work on the same 5V TTL level
My doubt is with the Y-splitter. Do you think we can use this Y-splitter like this?
So, This ESP32-CAM-MB board comes with an ESP32-CAM development board. It is meant for connecting the board to a PC and programming the board.
Please check out these two links for more clarification:
My question is:
If we are connecting the dev board to the printer through the CAM-MB board, the dev board doesn't get power since the printer is an output device. So the dev board has to be externally powered. For this, the solution I came up with is to use a Y-splitter from Amazon. It has a Micro-USB male on one end to connect to the MB board and a USB female for the Printer connection, and a Micro-USB female for powering the board.
FYI: I checked for this, The Micro-USB power line on the Y-splitter only supplies power, not data.
Is this setup OKAY, or are there any problems, Are we not supposed to do power and Serial through the same USB port (Micro USB port of the MB board)?
here USB-UART converter. it is "slave" USB device, the 3d printer is slave too. only PC is the USB host.
communication between two slaves is not possible.
for powering ESP32 board from printer you may want such cable (only power, no data lines):
you should connect free UART pins of ESP32 to UART pins of 3d printer. of course it is possible that USB-UART converters on both devices may cause interfering when you use its UART pins.
To my knowlage i think you cant do that with your specific board, but there is one that may be able to do that its ESP32-s3- wroom freenove. Its got two usb-c ports one uart and one otg. But im not sure so do your research.