DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Building Enterprise-Grade Real-Time IoT Dashboards with Vue 3, MQTT, and Kafka
  • OPC-UA and MQTT: A Guide to Protocols, Python Implementations
  • Connecting the Dots: Unraveling IoT Standards and Protocols
  • Real-Time Remediation Solutions in Device Management Using Azure IoT Hub

Trending

  • Monitoring Spring Boot Applications with Prometheus and Grafana
  • Code Quality Had 5 Pillars. AI Broke 3 and Created 2 We Can’t Measure
  • Real-Time AI Inference at Scale Using Cloud Run, GPUs, and Vertex AI
  • Building a Skill-Based Agentic Reviewer with Claude Code: A Practical Guide Using Skills.MD, MCP Servers, Tools, and Tasks
  1. DZone
  2. Data Engineering
  3. IoT
  4. Development of the Open-Source Telegram Bot for MQTT IoT

Development of the Open-Source Telegram Bot for MQTT IoT

Experience of development a flexible and an easy-to-configure for your needs open-source MQTT client Telegram bot.

By 
Anatoliy Bezgubenko user avatar
Anatoliy Bezgubenko
·
Dec. 17, 20 · Tutorial
Likes (3)
Comment
Save
Tweet
Share
15.6K Views

Join the DZone community and get the full member experience.

Join For Free

Today I will be sharing my experience in developing a flexible Telegram-bot. His purpose: obtaining information and controlling IoT devices via the MQTT protocol.

What’s so special? Because this is not just a bot with two-three hardcoded buttons to operate a light bulb (there are many examples of that on the Internet), but a bot that supports flexible subscriptions and commands to operate directly from the menu, without any changes introduced to the source code. It’s a ‘NoCode solution’, so to speak.

The bot is based on Go and the source code is made freely available on GitHab under MIT license. In this article, I’m talking about some technical aspects of implementation and the resulting functionality with usage samples.

What for?

Several factors have been pieced together. First of all, I have long wanted to transfer my smart intercom (sorry, it’s in russian) to something lighter and more universal than IoTManager. One Telegram-bot covers the entire multitude of devices and operating systems. Leave compatibility issues to comrade Durov. At last, I can open the intercom from my laptop.

Secondly, I really wanted to practice bot-writing, and I am very attracted to the very idea of managing something by means of a messenger. This is how Vas3k in his club made an admin panel via Telegram, isn’t that cool?

Functionality

Writing a bot with a few hardcoded buttons is tedious. I decided to make a more versatile solution with a customized user menu and display graphics support.

The following functionally was the basic goal:

  1. Multi-level user menu with the possibility of creating the following buttons: folder (for tree-like menu), single-value-command button, toggle button, multi-value-command button, show the last message received for the topic, draw chart
  2. Subscription to arbitrary topics (including receiving images)
  3. Storage of value history
  4. Manually sending a message to the topic

All the functionality is available directly from the bot menu without the need to change the source code. Edit the menu on the go and use it:

mqtg

You can give a try to my copy of the bot at @mqtg-bot. Notice that there may be some crashes because he is deployed on the free Heroku dyno. If he doesn’t respond to /start, now you know the reason. You can run your bot by consulting the README instruction.

Switch

The easiest one you could think of was to turn on/off the relay. For that purpose, I even assembled a small decorative desk lamp with a Sonoff Mini Wi-Fi relay inside. Let’s add a switch and to the bot menu and voilà:

scrolling

Chart Creation

It seems to me that every person who is interested in the IoT topic, first of all, connects the humidity and temperature sensor to Arduino or esp8266/32. My wife and I thus monitored the humidity in the flat after my daughter’s birth — in wintertime we experienced an issue when the house was centrally heated.

Subscribe to and receive a data from MQTT topic and draw a chart:

mqtg-bot

Subscription Parsing Data by JSONpath Expressions

To parse only the necessary value from received JSON you can use classic JsonPath expressions in the following format: $.home.sensors[0].temperature and bot will select and store only required data.

Receiving Images From Camera

One example of bot usage is to obtain IP camera images. Any binary data up to 256MB per message can be transferred via MQTT. Here we have endless usage options. For example, we can capture several images from an IP camera by signal from a motion sensor and send the images to Telegram. As an example, I sent images from the ESP32-CAM module on request. The Arduino sketch is stored in the examples folder of repository (it also sends reads data from the humidity and temperature sensor AM2301).

This is how it looks like:

cat on counter

A Couple of Implementation Features

The most time was spent writing the edited user menu, storing and loading it.

As a basis, I created the button interface, which describes a number of methods needed for button operation:

Go
 




xxxxxxxxxx
1
17


 
1
type ButtonI interface {
2
  GetType() button_types.ButtonType // each button must know its own type for marshalling
3
  GetName() string  
4
  // methods for working with buttons "commands", these are the actions that are performed when user clicks
5
  GetCurrentCommand() *CommandType 
6
  GetCommands() []*CommandType 
7
  AddNewCommand(*CommandType) 
8
  DeleteCommand(int)  
9
  // .... several methods are hidden here ....
10
  SetParent(*FolderButton) 
11
  GetParent() *FolderButton  // methods for tree-like menu
12
  GetButtons() *[]ButtonI 
13
  AddButton(ButtonI) 
14
  DelButton(int32)  
15
  // redefine json marshall/unmarshall methods
16
  MarshalJSON() ([]byte, error) 
17
  UnmarshalJSON([]byte) error 
18
}



Menu Marshaling/Unmarshalling

As you may have already noticed, the interface overrides the Marshal/Unmarshal JSON methods which are used to save/download the user menu to/from the DB.

When saving each object, the type of object must be marked so that it can then be deserialized.

Go
 




xxxxxxxxxx
1


 
1
func (b *FolderButton) MarshalJSON() ([]byte, error) { 
2
  b.Type = b.GetType() 
3
  return json.Marshal(*b) 
4
}



With unmarshalling it is a little more complicated as the structure of the user menu is not known in advance. We have to unmarshal JSON recursively in the map[string]interface{} and cast each object into a button of a certain type.

Go
 




xxxxxxxxxx
1
25


 
1
func parseDataMap(dataMap *map[string]interface{}) ButtonI { 
2
  var outButton ButtonI  
3
  fType, _ := (*dataMap)["Type"].(float64)  
4
  
5
  switch button_types.ButtonType(fType) { 
6
  case button_types.FOLDER: 
7
    var folderButton FolderButton 
8
    folderButton.Name, _ = (*dataMap)["Name"].(string) 
9
    buttons, _ := (*dataMap)["Buttons"].([]interface{})    // recursive data parser call
10
    folderButton.Buttons = make([]ButtonI, 0, len(buttons)) 
11
    for _, button := range buttons { 
12
      buttonMap, ok := button.(map[string]interface{}) 
13
      if ok { 
14
        ButtonI := parseDataMap(&buttonMap) 
15
        folderButton.Buttons = append(folderButton.Buttons, ButtonI) 
16
      } 
17
    }  
18
    outButton = &folderButton  case button_types.MULTI_VALUE: 
19
    var multiValueButton MultiValueButton 
20
    // fill in the required button fields
21
    outButton = &multiValueButton  
22

          
23
  // ... similar cases for all other button types ...  return outButton 
24
}



I have a strong feeling that saving/restoring menus in this way is a little bit complicated, but I haven’t thought of anything better yet. I would sincerely welcome advice on how to store user menus with different types of buttons and potentially unlimited nesting possibilities.

Coding Information in Callbacks

The data length in Telegram’s inline keyboard callback (the menu attached to the message) is limited to 64 characters.

To add all the necessary information to each button in the callback, I have created the following structure:

Go
 




xxxxxxxxxx
1
10
9


 
1
type QueryDataType struct { 
2
  MessageId   int64 
3
  Keyboard    KeyboardType  // inline keyboard type 
4
  Path        []int32       // where we are (to navigate a multi-level menu) 
5
  Action      ActionType    // basic action
6
  IntValue    int32         //  
7
  BoolValue   bool          // additional action data 
8
  Index       int32         //  
9
}



It is marshaled into protobuf and encoded into base64. So we have a total of 64 characters — that’s quite enough for me. How would you have done that?

What’s Next?

There are the following ideas for enhancing functionality:

  1. More flexible adjustment of charts (names for legends, axis min/max values, custom time axis format, etc.)
  2. Management of saved messages history
  3. Response to a received topic message (e.g. sending a command when certain data are received in the topic)
  4. Audio data reception

Please feel free to share any ideas you have in the comments box.

In Conclusion

I hope the article was of any help and does not look like self-promotion. I’m not looking for fame or money. It’s just a small contribution to open source and the IoT community. Two years ago I plunged into web development, but I still miss hardware tasks. The result was the creation of this project. Of course, the bot may require some additional lines of code. That’s why I need your response — that way I can see whether I should develop it further for the benefit of the community. Keep coding and have a nice day!

Links

  1. mqtg-bot — GitHub-repository
  2. @mqtg-bot — bot example hosted by me
  3. NoCode — the interesting article from Vas3k blog
MQTT Open source IoT

Published at DZone with permission of Anatoliy Bezgubenko. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Building Enterprise-Grade Real-Time IoT Dashboards with Vue 3, MQTT, and Kafka
  • OPC-UA and MQTT: A Guide to Protocols, Python Implementations
  • Connecting the Dots: Unraveling IoT Standards and Protocols
  • Real-Time Remediation Solutions in Device Management Using Azure IoT Hub

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook