HM-10 Bluetooth 4 BLE Modules

Updated 2017-11-14.
Since I first posted about the HM-10 the firmware has been update several times and some of the commands have changed. Therefore, I decided to redo the guide. For this update I am using modules with firmware 5.49 (regular) except the one I am using for the firmware update guide which started with v5.40 and becomes 5.47.

Firmware version 5.49 is now available from the Jinan Huamao website. There are 2 versions; regular and long name. The regular firmware does not have an updated read me so I don’t know what changes, if any, have been made. The long name firmware adds, you guessed it, long names. Device names can now be up to 29 characters. At the same time the iBeacon function and the ANCS function have been removed. Unless you desperately need long names I suggest you stay with the regular firmware.

2017-07-26 Firmware 5.50 now available.
2017-09.01 Firmware 6.01 now available (bug fixes, no new commands)
2017-10.xx Firmware 6.03 now available Extended the CO command. Added AT+MPIO (multi PIO control). See the readme file for details. The manual has not been updated at this time (Nov 2017).

2018-03-24. Jinan Huamao support say that the HM-10 (original ones, not copies) are compatible with Android 8. I do not have Android 8 so have not tried and cannot confirm.
They have now added a comment on their website saying the HM-10 works with Android 8.

2018-03 HM-10s with firmware 6.05 are now available but Jinan Huamao are not releasing the firmware. Not sure if this is just for now or permanently. v6.03 is still the latest firmware available for download.

It appears that Jinan Huamao are cracking down on fakes. Apart from not releasing the latest firmware the latest HM-10s have “HM-10″ screen printed on the PCB.

Image taken from the Jinan Huamao website

Image taken from the Jinan Huamao website

Bluetooth 4 BLE
HM-10 Services and Characteristics
Get Started With the HM-10
Getting an Arduino talking to the HM-10
HM-10 AT Commands: Using the Arduino’s serial monitor to talk to the HM-10
Scanning for other HM-10s
Arduino to Arduino using HM-10s
HM-10 to HM-10: Turning an LED on and off
HM-10 Programmable Pins
HM-10 Stand-alone MODE 2 and Controlling LEDs
HM-10 Stand-alone: Remote Light Sensor
HM-10: Add a second Custom Characteristic
Using the HM-10 with non-HM-10 modules (not fully working)
HM-10 as an iBeacon
HM-10 Updating the firmware
HM-10 Downloads




The HM-10 is a small 3.3v SMD Bluetooth 4.0 BLE module based on the TI CC2540 or CC2541 Bluetooth SOC (System On Chip). The HM-10 is made by Jinan Huamao and is one of many Bluetooth devices they produce including the HM-11 which is operationally the same as the HM-10 but has a smaller footprint with fewer pins broken out.

There are 2 versions of the HM-10; the HM-10C and the HM-10S

The HM-10C does not have the pads along the bottom (the usb connections) and has 26 pads instead of 34 which makes it a little cheaper to produce. There may be other differences (such as the type of crystal used) due to the date of manufacture. Operationally the two are the same though.

HM-10 Basic specs

  • +2.5v to +3.3v
  • Requires up to 50mA
  • Uses around 9mA when in an active state
  • Use 50-200uA when asleep
  • RF power: -23dbm, -6dbm, 0dbm, 6dbm
  • Bluetooth version 4.0 BLE
  • Default baud rate for the serial connection is 9600
  • Default PIN is 000000
  • Default name is HMSoft
  • Based on the CC2540 or the CC2541 chip

The latest HM-10s all appear to the the CC2541 chip. This is the same as the CC2540 except it is lower power and has a shorter range. The CC254x is based on the 8051 and runs at 32MHz.

The HM-10 is has become a very popular Bluetooth 4 BLE module for use with the Arduino. In part due to the standard UART serial connection that makes it fairly straight forward to connect to an Arduino. The UART layer is a good thing and a bad thing, it allows ease of use but it hides the BLE layer so you have no control over the actual BLE side of things. The HM-10 is Bluetooth version 4.0 only. This means it cannot connect to Bluetooth 2/2.1 modules such as the HC-06 and HC-05.

The HM-10 is controlled via AT commands which are sent over the serial UART connection. There are a host of commands, some simple, some more complex, and these are covered later.


HM-10 on a breakout board

The HM-10 is also available mounted to a breakout board that exposes the power and UART connections to breadboard friendly male pins. The breakout board includes a 3.3v power regulator that makes them 5V compatible. This makes them ideal for hobbyists like me. You should note that the RX pin is is still 3.3v and when using a 5v Arduino you should covert the Arduino’s 5v TX to 3.3v for the HM-10 RX.


Pin Description
STATE   Connection status
LOW when not connected. HIGH when connected
VCC Power in. 3.6v to 6v
GND Common ground
TXD Serial UART transmit
RXD Serial UART receive
BRK Break pin. When there is an active connection, bringing the BRK pin LOW breaks the connection

On board LED

The on board LED blinks when waiting for connection. It blinks half a second on, half a second off.
The LED becomes solid on when a connection is made and returns to blinking when the connection is broken.
The LED changes to solid on when pairing. After pairing it returns to flashing. It basically makes a connection to pair and so turns on the LED to show the connection status. After pairing is completed the connection is closed and the LED is turned off.

The behavior of the LED can be changed using the PIO1 command.
“AT+PIO10″ – Default setting. When not connected the LED blinks 500ms on, 500ms off. When connected the LED is solid on.
“AT+PIO11″ – When not connected the LED is off. When connected the LED is solid on.


The STATE pin is LOW when there is no connection and goes HIGH when a connections is established.


The BRK pin allows you to cancel a connection. When there is an active connection, bringing the BRK pin momentarily LOW breaks the connection. When there is no connection making the BRK HIGH or LOW has no effect. Although not strictly required, pulling the BRK pin HIGH for normal use will stop the pin floating.



There are lots of comments on the internet about fake HM-10s and even Jinan Huamao includes information in the data sheets. I do not see the non-HM-10s as fakes, I see them as similar devices with different firmware. To me if they were fakes they would copy the firmware.
I think a lot of the problem comes from how the non-HM-10s are sold, especially on places like ebay and aliexpress. You will often see modules sold as HM-10s when they are in fact not. One of the easiest ways to spot the non-HM-10s was the lack of a crystal, unfortunately you can now buy actual HM-10s without the crystal so the confusion is likely to get worse.


Bluetooth 4 BLE

BLE is not an upgrade to Bluetooth Classic, it is a different system with different intended uses. BLE works in a very different way to the earlier Bluetooth. BLE is designed for low energy applications and achieves this by using infrequent small packets of data. It is not really designed for continuous connections and large amounts of data. For this, Bluetooth Classic is a better choice. In essence, BLE achieves its low power consumption by not being connected very often, unlike Bluetooth Classic which maintains a constant connection.

While you can create a classic style connection using 2 HM-10s, and I give an example below, they were not designed for this and if this is all you need then you would be better suited with Bluetooth Classic modules like the HC-05s or a HC-05 and a HC-06.

There are 2 ways BLE devices can talk to each other; Broadcaster + Observer, and, Central + Peripheral. The HM-10 can use both methods.

  • With Broadcaster + Observer there isn’t a standard connection, the Broadcaster, usually some kind of sensor, sends out periodic signals (advertising packets) which the Observer listens for. The Broadcaster does not normally know if anything is listening or not.
  • The Central + Peripheral scenario is more like (but not exactly the same) as the classic connection. When the Central (master) device finds a Peripheral (slave) device it wants to connect to it initiates a connection and takes on the master role managing the connection and timings.


HM-10 Services and Characteristics

BLE is all about services and characteristics and like all BLE devices, the HM-10 has a set of services and each service has a set of related characteristics. Characteristics are where the values are, some are READ, some are WRITE, and some are READ and WRITE.

All the services on the HM-10 are predefined except one. This is a custom service that has one custom characteristic. Predefined services and characteristics are ones where the UUID and the name are set by the Bluetooth governing body. For example, the characteristic 0x2A00 is the device name and when a device has this characteristic it should always be the device name.

A full list of the predefined services can be found here and a list of the characteristics is here.

The HM-10 uses the custom characteristic to send and receive the data it receives over the serial UART interface. It works by setting the value of the custom characteristic to the value of the data to be transmitted. It then sends out a notification to the remote device to say there is new data available.
When you tell the the HM-10 to transmit “HELLO”, it first sets the value of the custom characteristic to “HELLO” and then it sends out a notification telling the remote device “Hey, I have new data, come and get it.” The remote device is scanning for the notifications and when it receives one it knows there is a new value, so it reads the data and then sends back a message saying “Thanks, I have it”.

The custom characteristic can hold up to 20 characters, this means to send a string longer than 20 characters the HM-10 splits the data in to 20 character segments and sends each one in turn until none are left.

UUID: 00001800-0000-1000-8000-00805F9B34FB

  • UUID: 00002A00-0000-1000-8000-00805F9B34FB
  • READ
  • UUID: 00002A01-0000-1000-8000-00805F9B34FB
  • READ
  • UUID: 00002A02-0000-1000-8000-00805F9B34FB
  • UUID: 00002A03-0000-1000-8000-00805F9B34FB
  • UUID: 00002A04-0000-1000-8000-00805F9B34FB
  • READ

UUID: 00001801-0000-1000-8000-00805F9B34FB

  • UUID: 00002A05-0000-1000-8000-00805F9B34FB

UUID: 0000FFE0-0000-1000-8000-00805F9B34FB

  • UUID: 0000FFE1-0000-1000-8000-00805F9B34FB

The main part of the custom service UUID (FFE0) the main part of the custom characteristic UUID (FFE1) can be changed via AT commands. A second characteristic can also be added.


Get Started With the HM-10

First, lets use an Android device to read the services and characteristics from the HM-10. Power on the HM-10, you can use an Arduino for this but all we need is 5V to HM-10 VCC and GND to HM-10 GND.
If done correctly, the LED on the HM-10 should be flashing. When a connection is established the LED will be become solid on.

Checking the HM-10 with an Android Device

Depending on your Android device and the version of Android you are running the HM-10 may or may not show up when searching for Bluetooth devices under the Android Settings.

Samsung S7 with Android 6.0.1 – Finds the HM-10 and allows pairing.
Sony Z3 Compact running Android 4.4.4 – Finds the HM-10 and allows pairing.
Huawei honor pro 4 running Android 4.4.4 – Does not find the HM-10

HM-10_S7_SCRN_001HM-10_Sony Z3_SCRN_001HM-10_honorPro4_SCRN_001

The Samsung S7 and the Sony Z3 Compact find the HM-10 through Settings but the honor Pro 4 does not. When using a BLE app all phones can find the HM-10 though.

If you device does not find the HM-10 under Bluetooth settings, try using the BLE Scanner app.

The modules can be paired using the default pin 000000 (unless you have changed it of course).

To connect to the HM-10 and to read the services and characteristics we need to use a BLE app. Here I am using BLE Scanner. There are many other similar apps available such as B-BLE.


Reading the characteristics of the HM-10 using using BLE Scanner

Open the BLE Scanner app and find the HM-10. Tap the CONNECT button to get the app to connect to the HM-10 and start reading its properties.


Clicking the small down arrows will expand the services and display the characteristics.

Tapping one of the HM-10_BLE-Scanner_009_R_20 labels will read the characteristic value. For example, under Device Name, tapping the HM-10_BLE-Scanner_009_R_20 reads and then shows the device name value.

R = Read value
W = Write Value
I = Toggle indications on and off
N = Toggle notifications on and off

Under Custom Service you can see the HM-10s default service and characteristic values. You can also see that the HM-10s custom characteristic has Read, Write, and Notify attributes.

I mentioned earlier that BLE is all about services and characteristics and the HM-10 works by setting the value of a custom characteristic to match the value of the data to be transmitted (the data received via the serial connection). This can be seen when using the BLE Scanner app.

Using the circuit and sketch from Getting an Arduino talking to the HM-10 (see below), connect the Arduino and HM-10 and open the serial monitor. You should have something like the below. Use the “AT” command to confirm communication is working. If it is the HM-10 will reply with an “OK”

Now, in the BLE Scanner app, connect to the HM-10 by tapping the CONNECT button.

Open up the “CUSTOM SERVICE” section and turn notifications on by tapping the HM-10_SERV+CHAR_003_N_Icon_015 icon.

Now, what ever you type in the serial monitor should appear as the value of the custom characteristic within the BLE Scanner app

To send text from the app to the serial monitor, tap the HM-10_SERV+CHAR_007_Wicon_015 Write icon and enter something in the popup text box. You will notice that the value of the custom characteristic changes to whatever you typed. The text should also appear in the serial monitor.



Getting an Arduino talking to the HM-10

Next we will connect the HM-10 to an Arduino and try basic serial communication and AT commands.

Note: AT commands only work when the HM-10 is not connected. After a connection is made the commands are treated as data. “AT” is the exception, the “AT” command breaks the connection.


Connect the modules as per the following:
– HM-10 TX pin to Arduino D8
– HM-10 RX pin to a voltage divider and then to Arduino D9*
– HM-10 GND to GND
– HM-10 VCC to +5V

*The pins on the actual HM-10 (the small daughter board) are 3.3v only. They are not officially 5v tolerant so use a voltage divider or something else to bring the voltage down to 3.3v.

I am using AltSoftSerial to talk to the modules. AltSoftSerial uses pin D9 for transmit and pin D8 to receive. You will need add the AltSoftSerial library to the Arduino IDE before you can compile the below sketches.


The HM-10 is a 3.3v device. The breakout board converts the +5v vcc to 3.3v to power the HM-10 but the RX pin is still 3.3v. Therefore, we need to bring down the Arduinos 5V TX pin to 3.3V. A simple way to do this is by using a voltage divider made from 2 resistors. I use a 1k ohm resistor and a 2k ohm resistor. 1K+2K = 3K. 2K is 2 thirds of 3K and 2 thirds of 5V is 3.3v.

The Arduino will see the 3.3v signal from the HM-10 TX pin as HIGH so we can connect the HM-10 TX pin directly to the Arduino RX pin (D8).

HM-10_SerialMonitor_011_VoltageDivider_800I am using a premade voltage divider. Because I make a lot of this kind of breadboard circuit I make small breadboard modules. One of these is a voltage divider.

If you want to be special you can place a LED on the STATE pin. Remember to add a resistor. The STATE pin is 3.3v when HIGH so using Ohm’s law we find that a 100ohm resistor would be OK. I didn’t have one on hand so I used a 220ohm one that I did have. Using larger resistors is OK but you shouldn’t use smaller ones. The LED will blink in sync with the on board LED.


Serial Sketch

After building the circuit upload the following sketch. This is a simple serial in, serial out program. Whatever the Arduino receives from the serial monitor it relays to the HM-10. What ever it receives from the HM-10 it copies to the serial monitor.

The HM-10 does not like end of line characters* (newline and carriage return (/n/r)) and normally you would not add them to commands. Here I am using them but noted that although the sketch prints the characters in the serial monitor it does not send them to the HM-10. This help make the examples easier to read.

*The upcoming 6.05 firmware adds free style line endings(add or not add /n/r).

The sketch uses AltSoftSerial which will need to be added to the Arduino IDE or copied to the library folder before you can compile.

//  SerialIn_SerialOut_HM-10_01
//  Uses hardware serial to talk to the host computer and AltSoftSerial for communication with the bluetooth module
//  What ever is entered in the serial monitor is sent to the connected device
//  Anything received from the connected device is copied to the serial monitor
//  Does not send line endings to the HM-10
//  Pins
//  BT VCC to Arduino 5V out. 
//  BT GND to GND
//  Arduino D8 (SS RX) - BT TX no need voltage divider 
//  Arduino D9 (SS TX) - BT RX through a voltage divider (5v to 3.3v)
#include <AltSoftSerial.h>
AltSoftSerial BTserial; 
char c=' ';
boolean NL = true;
void setup() 
    Serial.print("Sketch:   ");   Serial.println(__FILE__);
    Serial.print("Uploaded: ");   Serial.println(__DATE__);
    Serial.println(" ");
    Serial.println("BTserial started at 9600");
void loop()
    // Read from the Bluetooth module and send to the Arduino Serial Monitor
    if (BTserial.available())
        c =;
    // Read from the Serial Monitor and send to the Bluetooth module
    if (Serial.available())
        c =;
        // do not send line end characters to the HM-10
        if (c!=10 & c!=13 ) 
        // Echo the user input to the main window. 
        // If there is a new line print the ">" character.
        if (NL) { Serial.print("\r\n>");  NL = false; }
        if (c==10) { NL = true; }


HM-10 AT Commands: Using the Arduino’s serial monitor to talk to the HM-10

Open the serial monitor and you should see something similar to:

The HM-10 requires commands to be in upper case and normally without line end characters added. Here the sketch takes care of the line end characters for us. It does not send them to the Bluetooth module but will print them when echoing the command to the serial monitor main window. This is not really required but it means the commands will be on individual lines and be easier to read in the following examples. Normally, when working with the HM-10, everything is printed on one line.

Remember when using other sketches or a USB to serial UART adapter to set line endings to “No line ending” at the bottom of the serial monitor.

At the bottom of the serial monitor, set the baud rate to 9600 and using the above sketch means we can have line end characters selected:

To see if the connections are correct we use the “AT” command. The “AT” command is used to confirm communication is working and all it does is return an “OK”. “AT” can also be used to break an active connection.

Enter “AT” (no quotes) in the text box and click Send. If everything is working you should see “OK”.

To check what firmware the HM-10 has, use AT+VERR?

To check the modules name use AT+NAME?, or use an Android device and search for Bluetooth devices. The default name is HMsoft.

This only works when the HM-10 is in Salve/Peripheral mode. When in Master/Central mode it does not broadcast its name.

To get the modules address, use AT+ADDR?

Change the name using AT+NAME. Later I will be using 2 HM-10s and changing the names will help identify which is which. As you can see from the below I have changed the name to HMsoft-38A3. The “38A3″ are the last 4 digits of the mac address.

To get the modules Bluetooth characteristic, either use AT+CHAR? or use a BLE scanner.

To find the UUID use AT+UUID? This returns OK+Get:0xFFE0.


Common AT commands

Here is a list of the main AT commands. Remember that commands should be in uppercase and not include line ending characters (\r\n) unless you are using the above sketch in which case it does not matter if you include line end characters or not.

AT Test Command or Disconnect Command If the module is not connected to a remote device it will reply: “OK”
If the module has a connection then the connection will be closed. If the notification setting is active, the module will reply with “OK+LOST”
AT+NAME? Query the name Returns the name the module broadcasts such as HMsoft.
AT+NAMEnewname Change the name of the module Changes the name broadcast by the module. For example
AT+NAMEmyBTmodule changes the name to myBTmodule.
The maximum length for a new name is 12 characters.
AT+ADDR? Queries the HM-10s mac address Returns the address as a 12 digit hexidecimal number. For example, OK+ADDR:606405D138A3
Queries the firmware version number For example: HMSoft V540
AT+RESET Restarts the module. Returns OK+RESET
Will close an active connection while restarting.
AT+RENEW Restores the default factory settings. A quick and easy way to reset all settings.
AT+BAUD? Query the baud rate used for UART serial communication. This is the speed a host device like an Arduino uses to talk to the BT module. It is not the the speed used to send wireless signals between different modules. Returns the value 0-8, for example, OK+Get:0
0 – 9600
1 – 19200
2 – 38400
3 – 57600
4 – 115200
5 – 4800
6 – 2400
7 – 1200
8 – 230400
The default setting is 0 – 9600.
Remember that both devices, the Arduino and the HM-10 need to use the same baud rate. Garbage characters are usually a sign of mismatched baud rates.
AT+BAUDx Set the baud rate used for UART serial communication. x is a value from 0 to 8. See the above for wwhat value represents which baud rate.
Take care when using with an Arduino. The maximum baud rate the Arduino serial monitor allows is 115200. If you set the baud rate to 230400 with AT+BAUD8 you wont be able to talk to the module.
AT+NOTI Set the notification status If notifications are turned on, the HM-10 will reply to commands with a confirmation message or send out a message when certain events take place, like “OK” for the AT command and “OK+LOST” when a connection is broken.

AT+NOTI0 – turn off notifications
AT+NOTI1 – turn on notifications

AT+NOTI? Query the notification status Returns either 0 or 1:
0 – notifications are off
1 – notifications are on
AT+PIN? Query the PIN number used for pairing. Replies with a 6 digit number like “OK+Get:123456″ or whatever the current PIN number is.
AT+PIN Set a new PIN/PASS. The PIN must be 6 characters long..
AT+PIN123456 sets the new PIN number to 123456
AT+ROLE? Query the current Role; Master or Slave AT+ROLE? returns either 0 or 1.
0 = Slave or Peripheral
1 = Master or Central.
The default setting is 0 (Slave).
AT+ROLEx Set the device role. x is 0 or 1. To change to Slave/Peripheral mode use AT+ROLE0. This will return OK+Set:0
To change to Master/Central mode use AT+ROLE1. This will return OK+Set:1
AT+ROLEx mat require a reset before the changes take place.
AT+IMME? Query the start mode AT+IMME? returns either 0 or 1.
0 = Connect immediately (assuming a previous connection has been applied
1 = Wait for a connection command before connecting (AT+START, AT+CONN, AT+CONL
The default setting is 0 (connect on start).
AT+IMMEx Set the start up mode AT+IMME0 sets auto connect on start*
AT+IMME1 sets manual connection mode
AT+IMMEx is often used together with AT+ROLEx
AT+IMMEx mat require a reset before the changes take place.
AT+RESET Restarts the module
AT+RENEW Resets the module to the factory settings

*If there are no previous connections, HM-10s will auto-connect to any other HM-10 available (normally the one with the strongest signal). The HM-10 (by default) remembers the address of the last module it was connected to and if there is stored a previous connection this will take priority when the HM-10 is retrying to auto-connect.

For a full list of AT commands see the official data sheets:
Data sheet version 5.45 published Jan 2017.
Data sheet version 5.50 published Jul 2017.


Scanning for other HM-10s

For this example I am using 2 HM-10s; one connected to an Arduino as before, and a second simply powered.

To ensure I am using the default factory settings I have used AT+RENEW:

By default the HM-10 is in Slave or Peripheral mode and to scan for other devices we need to put it in to Central or Master mode. We do this using the AT+ROLE command.
AT+ROLE? queries what mode the device is in.
AT+ROLE0 sets the module to Peripheral mode.
AT+ROLE1 sets the module to Central mode.

In older versions of the firmware, AT+ROLE required the HM-10 to be reset either by cycling the power or by using the “AT+RESET” command. In the newer firmwares it auto resets itself (evident by the “” welcome message). Therefore, before we switch to Master/Central mode we need to turn off auto connect with AT+IMME. AT+IMME has 2 options; AT+IMME0 and AT+IMME1.
AT+IMME0 sets the module to auto connect on start up. This is the default mode.
AT+IMME1 sets the module to wait until it receives one of the connection AT commands (AT+START, AT+CON, and AT+CONNL) before attempting to make a connection.

If the modules are set to auto-connect, when we enter AT+ROLE1 the modules will auto connect before we get chance to enter the AT+IMME1 command (they auto-connect fairly quickly).

Use AT+IMME1 to stop the HM-10 auto-connecting.

Use AT+ROLE1 to put the HM-10 in to Central mode.

If you are using an older firmware you will now need to reset the module by either cycling the power or by using the AT+RESET command. If you forget to reset the AT+DISC command will not work.

To scan for other HM-10 modules use the Discover command AT+DISC?

Returned is the address of the module(s) found.


The “OK+DISCE” statement shows that the scan has Ended.

The results are stored in a list, the list starts at position 0, and can be used to make a connection using the “AT+CONNx” command rather than having to use the full address. The x is the index number or list position value. So, if the HM-10 only finds one module the result will be stored at index 0 and “AT+CONN0″ can be used to connect to it. When more than one module is found the addresses will be stored in the order they are discovered.

After a connection is made the list is cleared. This means if you break the connection you need to use the “AT+DISC?” command again. For experimenting with AT commands using “AT+CONNx” is fine, but I suggest using the full address to make sketches more robust and easier to write.

Note: AT+DISC? will only find HM-10s that are set to Peripheral mode. You cannot scan for modules set to Central mode.


Arduino to Arduino using HM-10s

Connecting 2 Arduinos using 2 HM-10s is fairly easy. It is straight forward to make a connection and once the connection is established the HM-10s UART layer does all the work for you. The UART layer does mean you have no control over the actual BLE details though. To make a connection, all we need to do is set the main module to manual connection, set to Central mode, and then use the connection command AT+CON. Once connected the HM-10 transfers data by setting the value of a custom characteristic to the data you are sending. The receiving device then reads the value.

For this example I have 2 Arduinos and each Arduino is connected to a HM-10. Both are wired up exactly the same.


and if you are wondering where the second HM-10 is getting power from; the connections are round the back.

I am using 2 different Arduino IDEs. Version 1.82 as the main IDE and version 1.63 as the secondary IDE. This gives me 2 serial monitors. The Arduino on COM6 is #1 and the Arduino on COM9 is #2.



HM-10 to HM-10 manual connection

To make a connection we:
Set the second module to Peripheral mode (the default setting),
Set the main module to manual start mode using “AT+IMME1″.
Then set the main module to Central mode with “AT+ROLE1″.
Then use “AT+CON” to connect. Of course you need to know the address of the second module which can be found using “AT+DISC?”.


Now we have the address of the second HM-10 we can connect using the address or the list index. Here I am using the address and so the command is “AT+CONA81B6AAE5221″. You would need to change the address to suit the modules you are using.

If the connection is successful we get “OK+CONNA” and the LEDs on the HM-10s stop flashing and become steady on.

Now, everything entered in one serial monitor is transmitted to the other.




HM-10 to HM-10 automatic connection

The HM-10 can automatically connect on start up without using a connection command. When there are 2 or more modules and one is in Central mode it will search and connect to another HM-10. This is fully automatic and you have no control over which module it connects to although it would normally pick the one with the strongest signal. Of course, if there are only 2 modules it does not matter. When you have only 2 modules, set one to Peripheral mode and the other to Central mode. They should now connect automatically. Nothing else is required.

If there has been a previous connection, the device last connected to will take priority over other modules. After you have made a manual connection, break the connection (cycle the power) and when ready enter “AT+IMME0″ (this turns on auto connect). Then reset the module by either cycling the power or using the “AT+RESET” command. The modules should now auto connect even when there are addition HM-10s in range.

The “AT+IMME1″ command stops the auto connect happening. Remember that you cannot use AT commands while there is an active connection (the commands are treated as data) (except “AT” which breaks a connection) so to enter AT commands you need to turn of the remote module and reset the Central one.


HM-10 to HM-10: Turning an LED on and off

We now try LED remote control. This is a very simply example, when a button switch is pressed a remote LED comes on. When the button switch is released the LED goes out.

On Arduino #1 we add a button switch to D2 and on Arduino #2 we add a LED to D4.

The switch on Arduino #1 is pulled down with a 10K resistor. This means pressing the button switch makes the Arduino pin go LOW to HIGH.
The LED on Arduino #2 is connected inline with a 220 ohm resistor (330 ohm is also OK).




The sketch on the master Arduino uses 3 AT commands to set up the Central HM-10 and start the connection. These are the same commands we used in the manual connection example above.

BTserial.print("AT+IMME1" );
BTserial.print("AT+ROLE1" );
BTserial.print("AT+CONA81B6AAE5221" );

This is not really the best solution but it works and it keeps the example easy to understand. Of course, if the HM-10 is already in Central mode and in manual start mode the first 2 commands are not required. The delays allow time for the replies. You could, if you wished, check for the correct reply before moving to the next command. Change the address to suit the modules you are using.

If you are using an older firmware you will need to add a “AT+RESET” command after the “AT+ROLE1″.

You could do away with these commands by using the auto-connect mode.

After this, the sketch checks the status of the pin connected to the button switch and if it has changed sends out 1 of 2 commands.

  • LOW to HIGH. The button switch has been pressed so we want to turn on the LED. This is done by sending a “1” to the remote module.
  • HIGH to LOW. The button switch has been released so we want to turn off the LED. This is done by sending a “0” to the remote module.

Note that we are sending ascii “1” and ascii “0” not the value 1 and the value 0.

// Very simple debouce.
boolean state1 = digitalRead(switchPin); delay(1);
boolean state2 = digitalRead(switchPin); delay(1);
boolean state3 = digitalRead(switchPin); delay(1);
if ((state1 == state2) && (state1==state3))  
    switch_State = state1;  
    if (switch_State != oldswitch_State)
          if ( switch_State == HIGH) { BTserial.print("1" );  Serial.println("1"); }
          else                       { BTserial.print("0" );  Serial.println("0"); }
          oldswitch_State = switch_State;

The secondary Arduino simply checks for a “1” or a “0” and if it finds one of them it either turns the LED on or turns the LED off.

void loop()
    // Read from the Bluetooth module and check if it is a command
    if (BTSerial.available())
        c =;
        // 49 is the ascii code for "1"
        // 48 is the ascii code for "0"
        if (c==49)   { digitalWrite(LEDpin,HIGH);   }
        if (c==48)   { digitalWrite(LEDpin,LOW);    }

Here are the full sketches.

On the first Arduino we have HM-10_Example_01_simpleLED_Central.

// HM-10_Example_01_simpleLED_Central
//  Simple remote control using HM-10s: LED on. LED off
//  Pins
//  BT VCC to Arduino 5V out. 
//  BT GND to GND
//  Arduino D8 (ASS RX) - BT TX no need voltage divider 
//  Arduino D9 (ASS TX) - BT RX through a voltage divider
#include <AltSoftSerial.h>
AltSoftSerial BTserial; 
byte switchPin = 2;
boolean switch_State = LOW;
boolean oldswitch_State = LOW;
void setup() 
    Serial.print("Sketch:   ");   Serial.println(__FILE__);
    Serial.print("Uploaded: ");   Serial.println(__DATE__);
    Serial.println(" ");
    Serial.println("BTserial started at 9600");
    Serial.println(" ");
    pinMode(switchPin, INPUT); 
    // connect to the remote Bluetooth module
    BTserial.print("AT+IMME1" );
    BTserial.print("AT+ROLE1" );
    BTserial.print("AT+CONA81B6AAE5221" );
void loop()
    // Very simple debouce.
    boolean state1 = digitalRead(switchPin); delay(1);
    boolean state2 = digitalRead(switchPin); delay(1);
    boolean state3 = digitalRead(switchPin); delay(1);
    if ((state1 == state2) && (state1==state3))  
        switch_State = state1;  
        if (switch_State != oldswitch_State)
              if ( switch_State == HIGH) { BTserial.print("1" );  Serial.println("1"); }
              else                       { BTserial.print("0" );  Serial.println("0"); }
              oldswitch_State = switch_State;

On the second Arduino we have HM-10_Example_01_simpleLED_Peripheral.

// HM-10_Example_01_simpleLED_Peripheral
//  Pins
//  BT VCC to Arduino 5V out. 
//  BT GND to GND
//  Arduino D8 (ASS RX) - BT TX no need voltage divider 
//  Arduino D9 (ASS TX) - BT RX through a voltage divider
#include <AltSoftSerial.h>
AltSoftSerial BTSerial; 
char c=' ';
byte LEDpin = 4;
void setup() 
    Serial.print("Sketch:   ");   Serial.println(__FILE__);
    Serial.print("Uploaded: ");   Serial.println(__DATE__);
    Serial.println(" ");
    Serial.println("BTserial started at 9600");
    Serial.println(" ");
    pinMode(LEDpin, OUTPUT); 
void loop()
    // Read from the Bluetooth module and check if it is a command
    if (BTSerial.available())
        c =;
        // 49 is the ascii code for "1"
        // 48 is the ascii code for "0"
        if (c==49)   { digitalWrite(LEDpin,HIGH);   }
        if (c==48)   { digitalWrite(LEDpin,LOW);    }

The above works well but what happens when you reset Arduino #1 when there is an Active connection? The LED comes on.

When you reset the Arduinos but not the HM-10s the connection remains active and the AT commands in the setup() function get sent as data and any “1”s in the data get recognised as LED Commands. There is a few things you can do to stop this happening.

  1. Before sending the AT commands, send a welcome message to see if there is an active connection. The remote device would reply to the message.
  2. Check the HM-10 STATE pin before sending the AT commands. The STATE pin is HIGH when there is a connection.
  3. Set the modules to auto connect and get rid of the AT commands. In my opinion this is the best option.

I leave this to you to implement.

A litle later we control an LED with just a HM-10, no second Arduino.



HM-10 Programmable Pins

The HM-10 has 10 pins that can be user controlled, a couple are input only, the others can be input or output. Unfortunately, the pins we can control are not available on the breakout board so we need to attach a connection directly to the actual HM-10 (the small daughter board).



Pin function

The pins we can use are PIO-2 to PIO-11(B).


PIO pins can be used as input or output:

HM-10 PIN Pin Function

NOTE: PIO-2 and PIO-3 can supply up to 20mA. PIO-3 to PIO-11 are only designed to supply 4mA.


HM-10 pin control AT commands

Set the output of a pin HIGH or LOW.
pin = pin number from 2 to B
0/1 = 0 for LOW 1 for HIGH
To set pin PIO-2 to HIGH we use “AT+PIO21″ and to set it LOW use “AT+PIO20″

Pin PIO2 can be used for PWN output.
x = a value from 0 to 9.

  • AT+PIO20 = LOW
  • AT+PIO21 = HIGH
  • AT+PIO22 = 100ms PWM
  • AT+PIO23 = 200ms PWM
  • AT+PIO29 = 800ms PWM

Note: The frequency is equal on off. So AT+PIO21 sets the pin to 100ms HIGH and then 100ms LOW.

There are different ways to read the pin state, either by reading each pin individually or reading them all at one time.

Read the current pin status.
pin = pin number from 2 to B.
To read the status for pin PIO2 use AT+PIO2? Returns the status in the form “OK+PIO2:0″ OR “OK+PIO2:1″.
0 = LOW and 1 = HIGH.

Note the double question marks.
Query the state of pins PIO2 to PIOB (11).
Returns a single byte in the form “OK+Col:00″ to “OK+Col:FF” that represents the current state of the pins PIO4 to PIOB (11). Bits 7 to 0 are mapped to pin POI4 to PIOB.

PIN 4 5 6 7 8 9 A B
BIT 7 6 5 4 3 2 1 0

Read the status of all PIO pins one time.
Returns 4 bytes in the form “OK+PIO?:0000″ to “OK+PIO?:03FF”. The last 3 digits are mapped to PIO0 to PIOB; this mean 3FF is 001111111111 or all HIGH. Pins PIO0 and PIO1 (the first 2 digits) are used by the system and there return 0.

Pins PIO4 to PIOB can be used for analogue input.
Read the voltage on a give pin.
pin = PIO pin from 4 to B.
returns the actual voltage in the form of a 3 digit float.
To read the voltage on pin PIOA (10) use “AT+ADCA?”, returns “OK+ADCA:2.80″ when 2.8v is applied to the pin and “OK+ADCA:0.00″ when the pin is LOW or no voltage is applied.

Set the rate that the pin state registers (inside the CC2541) are updated (querying pins actually queries the register not the pin).
freq = the frequency to update in seconds and is a 2 digit number 00 to 99.
The command will only accept a 2 digit number, “AT+CYC01″ rather than “AT+CYC1″.

Notice the double question marks.
Query the current frequency
Returns a 2 digit value in the form “OK+Get:00″ TO “OK+Get:99″
The default is 10 seconds.

Pin states can also be set when the HM-10 is first powered on with AT+BEFC and also when a connection is established with AT+AFTC.

Set PIO pin status before a connection / on power.
pinValues = a 3 digit number, 000 to 3FF, that is mapped to pins PIO0 to PIOB.Remember that PIO0 and PIO1 are used by the system and only the pins PIO2 to PIOB are available for use.
To set all the pins (PIO2 to PIOB) HIGH set BEFC to “001111111111” which is “3FF” with “AT+BEFC3FF”.
Pins set using BEFC can be changed later using AT+PIOxv.

Set pin status after a connection is established.
pinValues = a 3 digit number, 000 to 3FF, that is mapped to pins PIO0 to PIOB (same as AT+BECF). Remember that PIO0 and PIO1 are used by the system and only the pins PIO2 to PIOB are available for use.
To set pin PIO2 HIGH when a connection is established set AFT to “001000000000” or “200” with “AT+AFTC200″

Controlling the pins while the HM-10 is connected to a microprocessor, like an Arduino, doesn’t really make sense, after all it is probably better to use an Arduino pin. Where this can be useful is where the HM-10 is being used stand-alone.


HM-10 Peripheral mode: remote pin control

The PIO pins on a remote Peripheral mode HM-10 can be controlled remotely. We can do this because the HM-10 allows the Peripheral device to receive AT commands over wireless and the pins can be controlled with AT commands. When the HM-10 is used remotely and the AT commands are received over wireless, the pin control commands work a little differently. Here we need to to set either MODE1 or MODE2.

PIO pins can be used as input or output:


NOTE: PIO-2 and PIO-3 can supply up to 20mA. PIO-3 to PIO-11 are only designed to supply 4mA.

To tell the HM-10 we want to control the user PIO pins remotely we use “AT+MODE1″ and “AT+MODE2″.

Set the PIO pin control mode.
PIO2 and PIO3 to output and pins PIO4 to PIOB to input.

Set the PIO pin control mode.
PIO2 to PIOB as input.

In MODE1 only pins PIO2 and PIO3 are set to output. This means AT+PIOxv only works for these 2 pins. If you try to set one of the other pins the HM-10 will not respond, or, depending on the firmware, it may break and then re-establish the connection.



HM-10 stand-alone: Remote control an LED using MODE2

As a simple example to get started we will turn an LED on and off. First we will do this manually using AT commands and the serial monitor and once we have this working we can add a button switch to the Arduino and have the sketch do the work.


The Master or Central HM-10 is connected to an Arduino. The Peripheral or Slave HM-10 has an LED+resistor connected to PIO-2. I have the remote HM-10 powered from the Arduino but in practise you’d use a separate power supply such as a battery.

Central HM-10

Peripheral HM-10


Manual Process

After putting the circuit together upload the following sketch. The sketch uses the AltSoftSerial library which will need to be installed in to the Arduino IDE before you can compile the sketch.

//  SerialIn_SerialOut_HM-10_01
//  Uses hardware serial to talk to the host computer and AltSoftSerial for communication with the bluetooth module
//  What ever is entered in the serial monitor is sent to the connected device
//  Anything received from the connected device is copied to the serial monitor
//  Does not send line endings to the HM-10
//  Pins
//  BT VCC to Arduino 5V out. 
//  BT GND to GND
//  Arduino D8 (SS RX) - BT TX no need voltage divider 
//  Arduino D9 (SS TX) - BT RX through a voltage divider (5v to 3.3v)
#include <AltSoftSerial.h>
AltSoftSerial BTserial; 
char c=' ';
boolean NL = true;
void setup() 
    Serial.print("Sketch:   ");   Serial.println(__FILE__);
    Serial.print("Uploaded: ");   Serial.println(__DATE__);
    Serial.println(" ");
    Serial.println("BTserial started at 9600");
void loop()
    // Read from the Bluetooth module and send to the Arduino Serial Monitor
    if (BTserial.available())
        c =;
    // Read from the Serial Monitor and send to the Bluetooth module
    if (Serial.available())
        c =;
        if (c!=10 & c!=13 ) 
        // Echo the user input to the main window. The ">" character indicates the user entered text.
        if (NL) { Serial.print("\r\n>");  NL = false; }
        if (c==10) { NL = true; }

There are a few things we need to.
1. Set the Peripheral mode module to accept AT commands over wireless
2, Set the main module to Central mode
3, Make a connection
4, Use AT+PIO commands to turn the remote LED on and off

Set up the Peripheral mode device

To set up the Peripheral device we first need to tell it to accept AT commands over wireless. Unfortunately you cannot do this over wireless so we need to use wires and UART. You can use a computer with a usb-to-serial adapter or an Arduino and the serial sketch. I am using an Arduino and the serial sketch.


  • AT
  • AT+MODE2

Confirm the connections are correct and the HM-10 is reponding by using “AT” and then revert the HM-10 to default settings with “AT+RENEW”. HM-10s default to Peripheral mode.

Get the address. Used for connecting to later.

And finally set Mode to 2. This tells the HM-10 to accept AT commands over wireless.

The module with address A81B6AAE5221 is now set to Peripheral mode and set to allow AT commands over wireless. We can now move the module and add an LED to PIO 2.

Set up the Central mode device

After swapping the HM-10s we are ready to set up the Central mode module.


  • AT
  • AT+IMME1
  • AT+ROLE1
  • AT+PIO21 and AT+PIO20

“AT+PIO21″ sets pin PIO 2 HIGH and “AT+PIO20″ sets it LOW.

Make sure we are communicating by using “AT” and reset to the default settings with “AT+RENEW”.

Set to manual connection with “AT+IMME1″

Set to Central mode with “AT+ROLE1″

If you are using an older firmware you really need to update it. In the meantime you will need to reset the module before continuing.

Connect to the Peripheral mode module with “AT+CON88C255122F9E”. If the connection is successful the HM-10 will reply with “OK+CONNA” and the LEDs on the 2 HM-10s will stop flashing and be steady on.

To turn the LED on, use “AT+PIO21″

and “AT+PIO20″ should turn it off

Note. Depending on the power on and the on-connection settings, the LED may come on when the remote HM-10 is powered or when a connection is made. The PIO pin setting can be set for power on using the “AT+BEFC” command (before connection)and the pin settings can be set when a connection is established using the “AT+AFTC” command (after connection).


Automating the process

Since the remote device is already set up we do not need to change it. To the Central mode HM-10, we set to auto connect on start up by using “AT+IMM0″;

To stop the Central mode module auto connecting, turn off the remote HM-10.
On the Central mode module enter:

  • AT
  • AT+ROLE1

“AT+RENEW” resets the HM-10 to the default factory settings and since IMME0 is the default setting, we do not need to change it.


Now, when the modules are powered on they should auto connect.

We now add a push button switch to pin D2.


and now upload the following sketch.

// HM-10_Example_03_MODE2_LED
//  Simple remote control using HM-10s: LED on. LED off
//  HM-10 in Central mode connected to an Arduino
//  HM-10, no Arduino, LED connected to PIO 2
//  Pins
//  BT VCC to Arduino 5V out. 
//  BT GND to GND
//  Arduino D8 (ASS RX) - BT TX no need voltage divider 
//  Arduino D9 (ASS TX) - BT RX through a voltage divider
#include <AltSoftSerial.h>
AltSoftSerial BTserial; 
byte switchPin = 2;
boolean switch_State = LOW;
boolean oldswitch_State = LOW;
void setup() 
    Serial.print("Sketch:   ");   Serial.println(__FILE__);
    Serial.print("Uploaded: ");   Serial.println(__DATE__);
    Serial.println(" ");
    Serial.println("BTserial started at 9600");
    pinMode(switchPin, INPUT); 
void loop()
    // Very simple debouce.
    boolean state1 = digitalRead(switchPin); delay(1);
    boolean state2 = digitalRead(switchPin); delay(1);
    boolean state3 = digitalRead(switchPin); delay(1);
    if ((state1 == state2) && (state1==state3))  
        switch_State = state1;  
        if (switch_State != oldswitch_State)
              if ( switch_State == HIGH) { BTserial.print("AT+PIO21" );  Serial.println("The LED is ON"); }
              else                       { BTserial.print("AT+PIO20" );  Serial.println("The LED is OFF"); }
              oldswitch_State = switch_State;

The sketch is fairly simple. When the button switch is pressed “AT+PIO21″ is sent to the remote HM-10. When the switch is released, “AT+PIO20″ is sent. “AT+PIO21″ sets PIO-2 HIGH and turns on the LED, “AT+PIO20″ sets PIO-2 LOW and turns off the LED.




HM-10 Stand-alone: Remote Light Sensor

Here we create a remote light sensor using a stand-alone HM-10 and a Light Dependent Resistor (LDR). The LDR is connected to peripheral HM-10 pin PIOB. Using MODE1 means we can read the value of PIOB from the Central HM-10 over the wireless connection.


HM-10 Set up

The two modules have been set to auto connect using AT+IMME1 and the Peripheral module is in MODE1.


The Master or Central HM-10 is connected to an Arduino. The Peripheral or Slave HM-10 has an LDR connected to PIOB. I have the remote HM-10 powered from a bread board power adapter but you could also use a battery. The remote HM-10 has +5v on vcc and +3.3v going to the LDR.



The sketch is very simple, it sends “AT+ADCB?” and gets the reply. “AT+ADCB?” requests the voltage on pin PIOB of the remote HM-10.

//  Sketch: HM-10_Example_04A_RemoteLightSensor
//  Master HM-10
//  Pins
//  BT VCC to Arduino 5V out. 
//  BT GND to GND
//  Arduino D8 (ASS RX) - BT TX no need voltage divider 
//  Arduino D9 (ASS TX) - BT RX through a voltage divider
//  Remote HM-10
//  HM-10 vcc to +5V
//  HM-10 GND to GND
//  HM-10 PIOB to LDR/CDS
#include <AltSoftSerial.h>
AltSoftSerial BTSerial; 
char c=' ';
char reply[30];
int pos = 0;
void setup() 
    Serial.print("Sketch:   ");   Serial.println(__FILE__);
    Serial.print("Uploaded: ");   Serial.println(__DATE__);
    Serial.println(" ");
    Serial.println("The HM-10s should be set for auto connect");
    Serial.println("The remote HM-10 should be set for MODE1");
    Serial.println("BTserial started at 9600");
    Serial.println(" ");
void loop()
    pos = 0;
    while ( BTSerial.available() )
        c =;
        reply[pos] = c;
    reply[pos] = '\0';
    Serial.print("Reply = "); Serial.println(reply); 
    delay (3000);


I am just displaying the results in the serial monitor but you could set up something like a flashing LED on the Arduino to warn you if the light is on (or off).



HM-10: Add a second Custom Characteristic

By default the HM-10 comes with a single custom characteristic under a custom service and a second write only characteristic one can be added using the “AT+FFE2″ command. “AT+FFE2″ was added in firmware 5.45 and extended in version 5.50.

The second custom characteristic only has a WRITE property no READ and the value of this characteristic is sent to the serial UART connection the same as the FFE1 characteristic.

Query the status of the second custom characteristic. Returns either 0 or 1.
0 = not active.
1 = active.

AT+FFE21 start the second custom characteristic
AT+FFE20 stop the second custom characteristic

Although the second custom characteristic is WRITE only you can set it to have a response or not using the “AT+RESP” command.

Query the write response status. Returns 0 or 1.
0 = Write without a response.
1 = Write with a response.

AT+RESP0 set the second custom characteristic to no response
AT+RESP1 set to have a response.

Arduino sketch

Note: I am using sketch SerialIn_SerialOut_HM-10_01.ino which can be downloaded here or copied from below. This sketch adds line end characters to the serial monitor window to make the commands easier to see. The sketch also removes any line end characters before sending the data to the HM-10. This means you can have “Both NL & CR” set in the serial monitor.

After connecting and uploading the sketch, make sure the HM-10 is working by using the AT command. Then use “AT+RENEW” to restore factory settings.

“AT+FFE21″ starts the second custom characteristic. I am also adding a write with a response with “AT+RESP1″.

Cycle the power or reset the HM-10 for the changes to take effect.

The second custom characteristic is WRITE only. This means we can use it to send data to the HM-10 but we cannot use it to READ data. Anything we send to the HM-10 is output is the serial UART the same as the first custom characteristic.

To see it in action we can use the BLE Scanner app. Start the app, find and connect to the HM-10, expand the custom service and you should now see 2 custom characteristics:

In the FFE2 characteristic section click the HM-10_SERV+CHAR_007_Wicon_015 W button and a text input window pops up. Enter “HELLO” and tap send.
The characteristic value should change to “HELLO” and “HELLO” should also appear in the serial monitor:



Using The HM-10 With non-HM-10 Modules

Starting with firmware 5.42, Jinan Huamao changed how the HM-10 interacted with non Jinan Huamao modules. Prior the 5.42 the HM-10 connected and communicated with other modules just fine.

Using the later firmwares, I have so far had limited success with connecting HM-10s to the other UART BLE modules like the AT09 and BT05. The HM-10 will connect to the other module and data can be sent from the HM-10 to the remote device but I cannot receive data from the remote device. I had thought that using the self study function (AT+COMP1) meant that the HM-10 read the remote device characteristic’s properties and so meant that notifications would work. This does not seem to be the case though. I get the same results using the self learn mode and not using it.



HM-10 as an iBeacon

Not yet available. Being rewritten.


HM-10: Updating the firmware

Note: Updating the firmware is non-reversable. Once you issue the OK+SBLUP command there is no going back.

One of the nice things about the HM-10 is that Jinan Huamao update the firmware on a fairly regular basis and make all the tools and the latest firmware available from the download centre on their website. They also have a guide on uploading new firmwares.

Like the Arduino, the HM-10 has a boot loader that makes uploading new firmwares fairly straight forward. You will need a Windows PC and a USB to serial UART adaptor though.

Tools required

– Windows PC.
– USB to serial UART adaptor.
– If you want to be extra safe a couple of resistors to form a voltage divider.
– Firmware zip archive.


Get the files

From the download Centre down load the latest HM-10 firmware zip file, place it somewhere convenient such as your desktop, and unpack it.

Note: The firmware for the CC2540 and the CC2541 chips are not the same. You cannot load the CC2540 firmware on the CC251 chip.
All the HM-10s I have use the CC2541 chip and the only firmware available on the Jinan Haumao website is for the CC2541 chip but it is still worth double checking.

This is a zip archive for firmware 5.47 which contains the following 4 files. Other firmwares may be different.
The two files we need are HMSoft.exe, and HMSoft.bin. HMSoft.exe is a Windows app that does the uploading and HMSoft.bin is the actual firmware. HMSoft.exe does not need installing, just double click to run it.

Connecting the HM-10 to a PC

I am using a 5v UART adapter so I am using a voltage divider on the TX pin. Many guides online show connections from a 5V UART adaptors (and 5V Arduinos) TX pin straight to the HM-10 RX pin. I do not advise it. The HM-10 is a 3.3v device and the RX pin is not designed for 5V. To reduce the 5V signal from the UART adapter to 3.3v I am using a voltage divider made from a 1K ohm resistor and a 2k ohm resistor.
The HM-10s TX pin is also 3.3v but 5V UART adaptors will read 3.3v as HIGH so we do not need to convert to 5V. Since I am using the HM-10 on a breakout board that has a 3.3v regulator I can connect 5V VCC directly to the VCC pin on the board.

If you are using a 3.3v UART adapter then you will not need the voltage divider but you will need more than 3.3v to power the HM-10. The voltage regulator on the breakout board requires a minimum of 3.6v to operate.

VCC and GND from the UART adaptor are fed to the + and – rail on the bread board.



Checking we can talk to the HM-10

After setting up the connections we need to check that we can talk to the HM-10. Any terminal app can be used but to keep it simple I generally use the Arduino IDE.

A couple of things to remember. The HM-10 likes commands in uppercase and it does not like line endings.

Open the Arduino IDE and make sure the correct COM port is selected. On my computer this UART adapter is Port 6. You need to remember the port number for later.

Open the Serial Monitor, select “9600 baud” and “No line ending” at the bottom, then enter “AT”. If the connections are correct you will get an “OK”.

If you do not get the “OK”:
– Check you have the correct baud rate. The default is 9600.
– Check that you have “No line ending” selected at the bottom of the Serial Monitor.
– Check that you have the TX and RX connections the right way round.
– Check that you have the correct value resistors and that they are in the right order.

After confirming that we have communication working we can check the existing firmware version with “AT+VERR?”.
As you can see the HM-10 I am updating is version 5.40.

To put the HM-10 in to update mode use the “AT+SBLUP” command. You should get a “OK+SBLUP” reply and the LED on the HM-10 will stop flashing.

We can now close the Serial Monitor.


Actually updating the firmware

Open the folder containing the firmware files and run the HMSoft.exe file. If you are using Win7 or later you may need to run the app in admin mode.

Load the bin file, enter the correct COM port number and then hit the Load Image button.

The firmware file is first written and then verified.

When finished the Download completed successfully dialogue box will pop up and the LED on the HM-10 will start to flash again.

We can now close the updater app and reopen the Serial Monitor to check the new firmware version.

Firmware 5.46 adds 128 bit UUID compatibility
Firmware 5.47 adds the AT+DISA? command that “search devices and return full information”. Basically it scans for BLE advertisements.

As of June 6th, 2017, Firmware 5.49 is available.


Trouble shooting the firmware update

If you start the update and nothing happens you have probably left the Arduino IDE open. You need to close it to free up the COM port. The update app does not give an error message if the COM port is not available. It just sits there.

If you get a timeout error when updating try again. If you keep getting the error your UART adapter is likely to blame. I have a couple that are not good at high speed (I suspect they have fake FDTI chips) and they give errors when uploading and/or verifying.

If you crash out and the LED on the HM-10 remains solid on. It means it is still in upload mode. It will remain in upload mode even after cycling the power. Just start the update again using the update app.


HM-10 Downloads

HM-10 data sheet V5.50
HM-10 data sheet V5.45
Official update firmware guide
HM-10 Self-learning guide. Requires fw v5.42 or later.

HM-10 Sketches

Sketch: SerialIn_SerialOut_HM-10_01.ino
Sketch: HM-10_Example_01_simpleLED
Sketch: HM-10_Example_03_MODE2_LED
Sketch: HM-10_Example_04A_RemoteLightSensor



Jinan Huamao website. Note this sometimes gets reported as a malware site but I have not had any issues.
Jinan Huamao download page. The firmwares listed are for upgrade only and do not contain the whole file (no boot loader).

Using the HM-10 with App Inventor 2: Arduino, HM-10 and App Inventor 2


112 thoughts on “HM-10 Bluetooth 4 BLE Modules

  1. Pingback: Bluetooth Modules | Martyn Currey

  2. From Lars. Sent by contact form:

    I’ve been following your tutorials for the HM-10 module, thanks a lot – they are great! I’m working on a project of my own, where I got communication going between a ATTiny and UNO. Smooth :D

    But now I’m concerned with power consumption and want to throw the HM-10 module connected to the ATTiny in sleep mode between transmissions. The problem I’m having is tat while power is on, its connected to the UNO. While connected I’m not able to send AT commands it seems. Have you looked at this? Do you know how I can send AT commands to a HM-10 with a active connection when I want to sleep it to save power?

    • The default setting is once a connection has been made the AT commands are treated like data and get transmitted.

      I presume the HM-10 connected to the ATTiny is the Peripheral , in which case you can set the Peripheral to allow AT commands over wireless with the AT+MODE command. You can then send the AT+SLEEP command remotely or use the AT+PWRM1 command to put the module to sleep when the connection is broken.

  3. Hi, Im facing a problem dealing with these cc2541 based modules, maybe you can help me out. I would like to be able to know of the masters proximity from the slave device, with minimum power. How do you think I can accomplish this? What I was planing on doing was to get the module in master mode and scan for devices / compare with master MAC, but the FILT command was discontinued. Do you know why this happened? Cheers.

    • I somehow missed your question.

      You can use the RSSI value to determine proximity but be aware the value is not standard throughout different manufacturers.

      I am presuming you are using a HM-10 as the master device.

      The AT+DISA? command returns the advertising information from found devices and includes the RSSI value. AT+ DISA? will find non HM-10 cc2540/1based modules like the AT09 and BT05.

      The returned information is hex not ascii.

      OK+DISA –> Search start
      <OK+DISA:><Device Address><Device Type><Device RSSI><Rest data length><Rest data>
      OK+DISE –> Search end

      The AT+DISA? command requires fw 5.47 or above.

      I have been meaning to add this to the above guide but have not found the time yet.

  4. Hi Martyn:

    Great overview of the HM-10. Thanks for all your hard work putting it together!

    Some random notes:

    AT+DISI? when HM-10 is in central role scans for beacons in the area and returns all their info in ascii. A nice command for scanning the area.

    AT+ROLE1: When you are switching the HM-10 to central role, I believe that you have to do an AT+RESET command afterwards in order to make the central role take effect.

    AT+SCAN: As of firmware version 543, there is new scan duration command that you can use to make central role scans faster. The default is three seconds, which is quite slow, so it is nice to be able to change this to 1 second now.


    • Oops, forgot to mention AT+IMME…

      To place HM-10 in central role, you need to do:


  5. Al conectar con la aplicación Bluetooth Scan conecta sin ningun problema, pero, pero al tratar de agregarlo a la lista de dispositivo bluetooth, me indica que el dispositivo hm10 me aparese en el celular un mensaje que dice Vinculo rechazado por la tarjeta

  6. Hi Martyn,
    I’m doing something similar to your LDR example. I have a remote HM10 (which is connected to a sensor) and a central HM10. My problem is that I need to start the connection between the modules once the sensor detects, not before. How can I do this? I can´t send an “AT+CON” from the remote HM10 to do it. Thanks

    • I don’t think you can through software but you could try contacting Jinan Huamao on I have found them to be fairly helpful.

      Can the sensor to used to switch the power to the HM-10? Then have the HM-10s set up for auto connect. If not I would probably use another microprocessor.

  7. I haven’t been too motivated to use HM-10, but I wish I had known about this before……..
    The best rundown on HM-10 that I have seen. Great.

  8. Looks like a great overview of the HM-10.
    Hopwever I have a problem! Every time I type AT into the serial monitor, it disconnects the HM-10 and does not respond with OK. I have triple checked the wiring and thats OK, so any idea why this would happen?

    • When there is a connection “AT” will break the connection. Normally it will not give any response or reply.

      To get a response use “AT+NOT1″. Then when the connection is lost or broken the HM-10 will issue “AT+LOST”

  9. The module does not disconnect now, but I don’t get any response from the Arduino serial port, as shown in your article.
    Any idea how I can get it to respond?

    • Double check you have the correct connections; Arduino TX to HM-10 RX and Arduino RX to HM-10 TX.
      Double check the baud rate.
      Double check you have the correct pins defined in the sketch.

      After double checking, run the sketch, open the serial monitor and cycle the power to the HM-10. At power on the HM-10 issues “” as a welcome message. If you do not get the message in the serial monitor recheck everything again.

  10. Hi, great tutorial and I’m moments away from purchasing a couple of these things but do you happen to know what happens to any altered pin states should the central mode device lose power/connection with the peripheral device in a remote control situation – say I remotely set a normally low pin to high on the peripheral device to turn on an LED, will the remote device then set that pin low again immediately (or at least back to its confgured pre-connection state?) if the connection drops out? Thanks!

    • I haven’t tried this. If I get time at the weekend I will try a few experiments.

      When a new connection is established the pin(s) will be set based on the AFTC settings.

      I don’t know if losing the connection uses the BEFC settings or not. When I get time I will try.

  11. Hi,

    Is there any way of adding bootloader to the original firmware provided by the manufacturer as it is provided without?

    Original firmware have only 248KB (full firmware has 256KB).


  12. Im trying to run this hm10 module on the MEGA. Im using Serial1 as the bluetooth serial as I have connected it to pins 18/19 using the divider. Serial is my monitor which runs off pins 0/1, right? But I enter AT command into the serial monitor and I just get >AT printed out.

    • the >AT is echoed back from the Arduino, it is not the response from the HM-10.

      Yes, pins 0+1 are used for the serial channel to the computer. This is the main hardware serial channel.

      First thing to do is double check the connections. Then check them again. After this I would try using software serial or AltSoftSerial with different pins. This means you can use the sketch without changing it. If this works go back to the hardware serial.

    • I am having exactly the same problem, i can’t manage to receive an answer for the “AT” command. Something curious is that if WRITE from my phone to the module, i can see what i wrote in the Serial Monitor, but it doesn’t work from the Monitor to the phone (using BLE scanner app).
      If i do the same with a HC-06 module everything works just great!

      • This means HM-10 to Arduino is OK but you have a problem with Arduino to HM-10.
        I know you have the HM-06 working but it is worth double checking everting again. Make sure the voltage divider is connected correctly.

        As a test you can place an LED (+resistor) on the Arduino TX pin and see if it blinks when to send data.
        No blink means something wrong with the code.
        Blinks mean something wrong with the connection between Arduino TX and HM-10 RX

        • Thank you Martyn, my problem was with the voltage divider for the RX pin of the module. I wasn’t giving the pin enough voltage to represent a logic ‘1’

  13. hello
    The device shows up at BT05 on my phone and when I try to pair with it I see nothing… I connected it ble scaneer app. but not connected with mobile phone…what is the matter for it

  14. Hi, thank you for the detailed tutorial.

    I am trying to pair the HM-10 with another bluetooth device that requires me to provide a pin. I have successfully paid them, but have got now idea how I can get the HM-10 to send the pin (e.g. 512567) to this device.

    Would you know how to do this? Thank you!

    • The best option, if you have access to the other device, is disable password pairing. If you can’t do this it should work by setting the PIN on the HM-10 to match the other device.

      When pairing, the HM-10 will not ask for the PIN it will use its own PIN.
      (Assuming the HM-10 is acting as the Central device)

      • Thank you, this is where it gets challenging because my peripheral device is a Hexiwear ( wearable and each 6 digit pin it sends back is random. I have attempted to hack the hexiwear to always return the same pin and configure the HM-10 to use the same pin but there isn’t a response from the Hexiwear.

        It seems that there needs to be some kind of command that lets the HM-10 send a pin code to the hexiwear when it asks for one.

        In the raspberry pi, the command line utility that lets the central device provide the pin is bluetoothctl. I am not sure if there’s an equal in Aruduino, or have I gone beyond what a HM-10 could do.

        • Unfortunately the HM-10 does not have the facility to ask for a PIN, it just uses the one saved by the user, and so I doubt it is the right solution here.

          You will probably need to look at other BLE modules where you have control over he Bluetooth side of things, such as those from Nordic, or an Arduino with built in BLE like the 101.

          • Thank you Martyn, this has been a good learning journey and your blog post helped a lot.

            I learnt the possibilities and limitation of HM-10 and I am planning to approach my project differently. Instead of trying to connect to the hexiwear, I will probably try to build a prototype that uses the HM-10 with Arduino in the same way you connect 2 HM-10s.

            Thank you again!

            • Hi jackson I also got same problem you are facing which is pairing hexiwear to HM-10, will you be able to connect it? is there any other way i could connect hexiwear to arduino using some other ble modues if can u please name them .

              • actually, Hexiwear has the mode that dont need to Auth and Pin, so just using HM-10’s AT command: AT+TYPE0 (not pin and auth). Then it can connect. However, I just stop at connecting step. I can not receive or send data from HM-10. I am finding solution

  15. I was having some doubts about your suggestion to add a voltage divider to the RX pin, so I did some research. Hard to find a solid answer, but I did find an interesting discussion in the Arduino forums about a similar issue with another module. Paul__B suggests that using a diode might work even better than resistors (but clearly you are correct that resistors will likely get the job done).

    The electronics details are beyond my understanding, but just for the record, here’s a link of the discussion:

    I have been connecting my arduino pins directly to the HM-10 breakout RX with no bad results to date, but as someone mentioned, that doesn’t prove that what I am doing is correct! :-)

    • The spec for the CC254x chip used in the HM-10 clearly states it is a 3.3v device.

      Some time ago there were similar discussions about the HC-05 and HC-06. The specs stated the chips were 3.3v but people reported using 5V without problem. Other people report problems. I did some TTFs on 3 HC-05s by connecting the RX pin directly to 5V and then ran a a serial send in a loop. The RX pin on all the HC-05s eventually died. Since then I have always advocated better to be safe than sorry.

      There are many ways to reduce the voltage, I use resistors because I have them and they are very common. I have used diodes and also power regulators but prefer resistors.

      Diodes will also work, and I believe they react quicker than resistors, as long as you know the voltage drop, the 4001/4007 are usually (but not always) about 0.7v so 2 in series works (5v – 1.4v = 3.6v. 3.6 is just about OK). At least with resistors you can calculate and achieve exact voltages and resistors tend to be far more common in a hobbyist parts bin.

  16. Hello,

    Thanks for making this big tutorial about hm10, It is helpfull.

    I’m currently struggling with a functionnality I don’t succeeded in doing with HM 10; I would like to read characteristics from a distant devices throught HM10 (a mi flora).

    Communication diagram:
    ESP8266 HM10 Mi flora

    Communication between ESP8266 and HM 10 is OK and working well.

    I would like to read the temperature/moisture … , the corresponding characteristics can be found on existing python scripts working with BLE dongles or integrated BLE chips:

    With HM 10 I’m not able to read the data from the xiaomi miflora. Here what I have done:
    -Discover the Mi flora with the AT+DISI? command and recover the adress–>OK
    -connect to the Mi flora adress in master mode with AT+CON –>OK
    I get an OK+CONNA and after 3 carriage return, nothing happens after…
    I tried after to question characteristic but it returns only the HM 10 characteristic.
    I tried to put the HM 10 in slave mode but the connection to the mi flora fail.

    I’m using HMSoft V545

    Do you think it is possible to recover data from the miflora, if yes do you have some infos to give me?

  17. thank you for your detailed description of the HM-10 BLE module, especially the characteristic description

    i would have a few questions :

    after speed testing with a cortex m0+ (nxp lpc824 30 MHz) with dedicated speed test firmware and either a QT 5.9.1 speed test app on kubuntu 16.04 or an android speed test app on nexus 7 2013, my tests so far have discovered that the hm-10 can at best handle 1 byte / ms in and out
    if i compare this to a regular bt-spp based module it’s by a factor of 5 slower, 5 bytes / ms at 57.6 kBd (max speed at this baud rate) … maybe faster if i up the baud rate

    what i’m after is more inforrmation on the hm-10 :

    hm-10 min “connection interval” time … the ble specs defines it as 7.5 ms … what’s the hm-10 data ???

    hm-10 max “number of pkgs x-mit per connection event” … one or more ???

    since i need more throughput, but would like to stay with low cost chinese devices i was wondering if u had a chance to evaluate the hm-16, which is also cortex m0 based and claims to be faster

    HM-10/11 speed is about 2KB/seconds
    HM-16/17 speed is about 3-8KB/seconds

    as well as lower power

    HM-10/11 in automatic sleep mode 50~400uA
    HM-10/11 in active mode 8.5mA
    HM-16/17 in automatic sleep mode 50~1200uA
    HM-16/17 in active mode 6.5mA

    any ideas on your end would be highly appreciated

    cheers Klaus

  18. just found this as by-packed with the which partially answers one of my questions

    actually it was part of the spec sheet, and i missed it

    HM-10/11 CC2540/1 V538
    1. Add AT+COMI command, config Minimum Link Layer connection interval
    para1 value: 0 ~ 9; Default: 3(20ms);
    0: 7.5ms; 1: 10ms; 2: 15ms; 3: 20ms; 4: 25ms; 5: 30ms; 6: 35ms; 7: 40ms; 8: 45ms; 9: 4000ms
    2. Add AT+COMA command, config Maximum Link Layer connection interval
    para1 value: 0 ~ 9; Default: 7(40ms);
    0: 7.5ms; 1: 10ms; 2: 15ms; 3: 20ms; 4: 25ms; 5: 30ms; 6: 35ms; 7: 40ms; 8: 45ms; 9: 4000ms
    3. Add AT+COLA command, config Link Layer connection slave latency
    para1 value: 0 ~ 4; Default: 0;
    4. Add AT+COSU command, config Link Layer connection supervision timeout
    para1 value: 0 ~ 6; Default: 6(6000ms);
    0: 100ms; 1: 1000ms; 2: 2000ms; 3: 3000ms; 4: 4000ms; 5: 5000ms; 6: 6000ms;
    5. Add AT+COUP command, switch slave role update connection parameter
    para1 value 0, 1; Default: 1(Update on);
    0: Update off; 1: Update on;

  19. sorry for all of my posts … but my hm-10 is now stuck in fw download mode and i have no idea on how to get out of it

    i use my own optically isolated ftdi based usb to 3.3 V interface board which also feeds the hm-10 on the other end of the wires with 3.3 V power

    i know i don’t really need this optical isolation, but i always use it for years now and it always worked on everything … the power through feed is enabled with jumpers

    i switched the module down from 56k7 to 9k6 baud and put into the fw load mode

    the hm-10 led stays on, but the fw update pgm gets always into timeout

    there is only one restriction with my ftdi board, the max supported baud is 57k6 which is limited by the optical isolators, but i’m running now on 9k6

    any thoughts on how to get the hm-10 out of this fw upload mode

    maybe some others might run into a similar situation

    the only other observation i would like to mention was that my cpu chip did not have any readable info about 2540 or 2541 on it, but all other of my modules stated 2541

    tx, cheers Klaus

    • The HM-10 will stay in this mode until a new firmware is successfully uploaded. I believe the upload baud rate is internal to the upload app and the HM-10 boot loader and is not effected by the user set baud rate.

      I suspect the max speed on your board is not high enough. Do you have access to another usb serial convertor?

  20. i get about 1 byte per ms and if i think about right that the hm-10 has a default “connection interval” of 21 ms and one pkg contains a max of 20 bytes, then this would be the 1 byte / ms … just a thought

    now the hm-10 has an at cmd of AT_COMI which is supposed to change the link layer min connection interval down to 7.5 ms (ble min specs) one would think that this might get the speed up by 3

    well … not so fast … my hm-10 rev is 527, which does not support this cmd and the upgrade to a newer rev has bricked the only one i had soldered into my regular test setup … all others are in dedicated hw and i might have some somewhere, but that’s it for today

    thanks to i have now a few hm-16’s on order … what a day

    maybe this helps others to get a better understanding of the bandwidth limits of ble … assuming my thought are correct

    cheers Klaus

    • I haven’t done a lot with bench marks on the HM-10 and have only really used them with Arduinos which adds its own speed limits. When I need better through put or better control I use a different module.

      It wouldn’t hurt to contact Jinan Huamao. I have found them fairly responsive to emails and I have found them helpful :

  21. CHEERS! Just here sharing my experience that may help somebody reading comments, or maybe you (Martyn) could update the post with my hint!

    Used a CC-41-a module (A.k.a “HM-10 clone”) which I flashed firmware+bootloader v540 from this guide:
    Everything done with an Arduino MEGA without no voltage divisor for serial transmission (AFAIK thats risky, but I had no problem) and also using 5V as Vcc.

    Then (trying to update it to v550 or higher) I ended up here looking for a solution with the “timeout error”, and your advise about UART and speed problem helped me to figure it out!
    It was my Arduino sketch when doing Serial.begin(9600) ! Even when 9600 it’s the baud rate recommended, it looks like that’s too slow for the updating software! So I used 115200 as baud rate in the Arduino sketch and worked as spected!

    Hope it helps

  22. Hi martyn I have an issue connecting hexiwear to HM-10 since the hexiwear requires me to provide pairing code in to my HM-10 module. What are the other possible ways i could connect my hexiwear to an arduino using BLE module(since HM-10 doesn’t have the feature of asking for PIN which you mentioned in oneof the commands above).

  23. For what its worth, I’d like to add a few observations which others may appreciate.

    I’ve been working with a couple of Chinese clones (I’d like to call imitations).
    They are sold as HM-10’s but we all know the story about this by now.

    In the terminal, I extracted the firmware versions to be Bolutek- VER 3.0.6
    Both my LG G5 and an older Samsung G4 would see the BLE, but were refused connections via bluetooth on the phones.

    And so I upgraded the firmware to ver. 540, and bingo!…both phones can now connect.
    Going further, I tried upgrading the firmware as Martyn suggests…
    The upgrades went well, however EVERY other version of firmware beyond 5.4 would not allow my phones to connect.
    And so, I went back to pins 7,8,and 11 via the arduino nano on the cmd prompt to downgrade back to 5.4
    All AT commands work and a connection can be made by both phones.

    Kudo’s to Martyn for an outstanding site and such well documented info on these little wonders..
    I’m anxiously waiting for the control panel app to be BLE compliant…
    That will indeed be the cats miou!

    • After 5.40 Jinan Huamao changed how the HM-10 interacts with non- Jinan Huamao modules and introduced Self Learning Mode. I haven’t done anything with this (been meaning to just never got round to it) and as far as I can tell you need to match the UUIDs with the remote module and the the HM-10 will find out what properties the characteristic has (such as read/write/notify).

      With fw 5.40 and before this appears to be the default behavior.

  24. Thanks for this incredible post!
    My laptop is running Windows 7 64 bits, and supports bluetooth 2.0 instead of 4.0 BLE. Therefore, I will need a USB dongle with bluetooth 4.0 BLE. Do you think any dongle with bluetooth 4.0 will work? I’ve found this one:
    Thanks again!

    • Please be aware I haven’t used the HM-10 with this kind of beacon so the below are my thoughts only.

      The HM-10 is very limited in what it can do, and, in my opinion, does not represent true BLE. As a basic beacon scanner it should be OK but you may have issues if you want to connect to the beacon.

      In this case I would recommend another nRF module rather than the HM-10. One where you can create services and characteristics. Something like the one used in this video:

  25. Hi Martyn, thank you for your helpful tutorial on HM-10 Module. I have a module with the TI CC2541 chip but without the external 32kHz crystal connected to an Arduino UNO that reads a sensor. When arduino reads a data, sends it to the bluetooth module but what the reads on my BLE Scanner is often different from what arduino sent. Sometimes BLE Scanner receives a part of the initial string sometimes data are wrongs. Can it be due to the different firmware?


  26. Hey Martyn!
    Thanks a lot for all the information on this post. Really helped!

    One quick question:
    Is there any advantage on having the second write-only characteristic activated? For example, can you achieve a higher-speed or more robust data transfer?

    I’m sending packets of 100 bytes from my phone and some times it looks like HM-10 cannot keep pace (does not send the ACK message, [at least I don’t see it from the app]), so I was wondering if splitting the write and read in different services would help mitigate that.

    Thanks in advance!

    • I haven’t really done a lot with the second characteristic and for the few projects where speed and data integrity were critical I used a different system.

      I do suspect that the problem is likely to be with the UART interface though. I presume you are using UART, if so, what baud rate are you using? If it is fairly slow try increasing it. If using an Arduino, be wary of software serial. It does not like high speeds. If possible use hardware serial or at the very least AltSoftSerial.

  27. Hi Martyn! Thank you very much for creating such a helpful resource!
    I’ve looked through all the sections on your site and can’t find a clear answer to a question I have… I’d like to recreate the remote light sensor project above, but with a standalone HM11 module and using an android or iOS app to read the voltage value on the HM11 input pin (PIO3 it seems). Is this possible to do?



    • I’m not at home so can’t check but…

      The HM-11 can be used exactly the same as the HM-10 except it has less pins so the remote example above should work the same.

      For the battery, check the data sheet. The HM-10/11 has the facility to put the voltage level in to a characteristic. Can’t remember which or how though.

      It may also be worth while checking out the HM-sensor firmware. Again, I can’t remember the details but the docs are available on the Jinan Huamao website.

      • Thanks Martyn! It had occurred to me that using the HMsensor configuration might make it easier… I will flash the HMsensor firmware to the HM11 to see the difference. It is not the battery level that I want to transmit, simply a variable voltage on the input pin (it seems only PIO3 can be set up for this on the HM11). Perhaps it is my lack of knowledge of how to read the sensed pin data from the transmitted characteristic, but I can’t seem to read a varying voltage input to the HM11 using any of the iOS apps (HM10Control, Bluetooth Serial Pro, Liteblue, BLE Scanner etc.)

        • Update: Putting HM11 into Mode1 and using the AT+COL?? or AT+PIO?? command returns state changes on PIO3 pin (the only input enabled pin on HM11) at a rate set using AT+CYC[t], but does not recognise AT+ADC command. Suspect ADC function on HM11 is disabled – have emailed JNHuamao to confirm

  28. Hey,
    I am trying to create a device that has HM10 to connect serially with my laptop via its built in Bluetooth.
    My HM10 can pair with my laptop. However, I cannot send any data serially because I do not know how to setup my built in Bluetooth to act like a serial port.
    I tried to create a new COMM port but it won’t find my HM10.
    Any help please?

  29. Has anyone had any luck connecting to these things on Android 8.1?

    I have a CC41-A clone, and my Pixel 2 nor my wife’s Pixel 1 (both on 8.1) won’t even find them in BLE scanning apps. I have been able to issue AT commands over the serial interface successfully via an Arduino, but no matter what I just can’t see it in Android. I’ve tried AT reset, changing the name, etc, but with no luck.

    I thought I may have a dud unit with a bad aerial or something, but I fired up my RPi 3 and can actually see it when I scan with hcitool there. So it seems to be late version Android specific perhaps?

    There seems to be a tiny bit of discussion around this online, but I can’t find anything particularly useful – eg

    At this point I’m thinking I’ll just use an HC-05 or something and ditch BLE for my application, but it’s a bit of a pain as I’ll need to wait for more parts to arrive. Cheers!

    • It an issue with Android 8. There are still many problems reported with Android 8 in general and a quick google “android 8 ble not good” will return quite a few results. Google say they are working on a fix but the BLE issues were reported last year and the problems still persist.

  30. This is a great writeup, thanks a lot. I have one question left though. Is there a way for the bluetooth module to scan for smartphones it has been paired to before and auto connect to them the same way a bluetooth headset does? Somehow nobody was able to achieve it as far as my research shows.
    I do not need to communicate with the smartphone, just connect to them automatically as an authentication process for a switch I want to trigger afterwards. Is there a way without using an android app for that?

    • This is not something I have done with 2 modules but not with a smartphone but I have some thoughts.

      The phone, by default, is the master device. This means it is the phone that scans for the BT modules and connects when it finds a BT module it has previously been paired with. For the BT module to be the master device would require additional software on the phone.

      Headsets use the HID profile which has different connection methods (such as auto connect) and I am not sure auto connect works with the HM-10. I haven’t tried though.

  31. Great tutorial. I am using the HM-11 for a project and having terrible luck getting it working. The firmware on the HM-11 is V546.

    I am trying to scan for BLE peripherals and iBeacons nearby but I am only able to find my devices if they are within about 1 foot. Once I move the device farther from that the HM-11 is unable to find it. I am using other HM-11’s and some nRF51822 boards for the peripherals/iBeacons.

    To scan for peripherals:
    AT+ROLE1 //set as master
    AT+IMME1 //wait for commands after reset
    AT+RESET //reset
    AT+DISC? //start discovering

    To scan for iBeacons:
    AT+ROLE1 //set as master
    AT+IMME1 //wait for commands after reset
    AT+RESET //reset
    AT+DISI? //start discovering

    I have my power set at 6dbm (AT+POWE3) on the HM-11 central. I am using a 100ms advertising interval for the peripherals/iBeacons. I am still unable to find my peripheral/iBeacons further than about 1 foot away which is quite a problem. I am pretty sure that my hardware is good because I have tried it on multiple HM-11’s which I bought from Digikey.

    Has anyone experienced this? Any help would be greatly appreciated.

  32. Comment from Alex:

    Thank you for your most informative posts, I have found them really useful and clear in my Arduino dabbling !
    I am interested in trying to connect a DS18b 20 to pin 34 (?) of the HM10 and henceforth being able to include the temperature information in the advertising data, to be read by another HM10, connected to an Arduino (Mega).

    Looking at your posts, it seems you know how this could be made to work, yet I haven’t seen exactly how to do this. Please could you point me in the right direction?

    I was sort of assuming that one would use AT commands to instruct the HM10 to read the one wire data from the DS18b 20 on pin 34, then attach that data to the advertising data, but can this be done once, or does this AT command have to be sent to the remote HM10 every time you want the temp data?

    I would be most grateful for any assistance you could provide.
    Kind Regards

  33. Hi, thanks very much for this page as it has been incredibly useful, although i have managed to get a few knock-off ‘HM-10s’ and have got two working and connecting. I have also managed to unknowingly purchase two MLT-BT05 chips, which look very similar to the HM-10s. I have ran your code and can get the serial monitor to display text i send through my phone to the MLT-BT05 however i can’t get the AT commands to work.

    Using the normal AT commands there is no response though after playing about with it I’ve noticed it will respond to “ATAT” with OK (this will not break an active connection) and other doubled up commands such as “AT+HELP?AT+HELP?” wit ERR.

    As far as i’m aware i have it set up correctly with 9600 BAUD and Both NL & CR (as the MLT-BT05 requires). Have you seen anything like this before or can you offer any advice. any help is much appreciated.

    Cheers Ciaran

  34. After update Android OS from 7.0.x(Nougat) to 8.0.x(Oreo)
    HM-10 is no longer discoverable on the phone at all.
    Have anyone facing this problem?
    I’m not sure is this Android OS bug or HM-10’s problem.

  35. Dear all,

    we are working on HM10 and firmware version is 2.0.
    We are trying to update the firmware using arduino but nothing reply from it.
    We follow as same step as mentioned but still get same issue.

    AT+HELP command not work so please suggest right direction what we do ?


  36. Hello,
    We are using HM10 and version is 2.0 so we need to update the firmware but
    when we send command “AT+SBLUP” but get error resturn back.

    need help to sort out issue.


  37. Hi Sir
    i am using HM-10 BLE device and i want to upgrade firmware via Arduino so i getting error .I done this step
    STEP 1 CCLoader.ino skecth upload with Arduino IDE
    STEP 2 Connect HM-10 to Arduino WIth
    STEP 3 open CMD and Wirte CCLoader.exe 9 HMSoft.bin 0 or 1
    in Step 3 i will get Wait for Arduino respond and Nothing is Done

      • Hi Sir
        i am using HM-10 version 2 upgarde firmware so
        i Done Send Command AT then replay is OK
        but i Send command OK+SBLUP but no responce and
        i open HMsoft.exe Load bin file but Error geting “”Timeout Waiting from target responce

  38. Hello! Would you like to tell me, what i need change? I used first scatch(simple serial) and ble scanner. I wrote in terminal and i saw value in ble scanner. I have a problem, when i wrote command AT, then i saw it in value without response.

  39. i wanted to update my firmware but and error occurs, “Timeout waiting for response from target”. please help thank you in advance

  40. Hi, thank you for your article. I have a problem that when I enter commands such as “AT+CON” OR “At+disc?” They output nothing

  41. Very helpful doc.Thank you.

    Occasionally, I get a null character back at the end of the response to AT+RESET or AT+RENEW. It’s easy enough to add some code to throw it away, but do you know what’s causing it?


    • For the older firmware’s I haven’t come across this or I simply haven’t noticed.

      If you are using a new module with the latest firmware (6.05 ) then it may be line end characters.

  42. Would it possible to configure master device to switch among multiple Peripheral modules?

    This is may be scenario if you need to read samples from multiple sensors from a central devices via bluetooth.


    • Using the HM-10 to would need to connect to each remote device in turn.
      1 – connect to remote #1
      2 – read data
      3 – disconnect
      4 – connect to remote #2
      5 – read data
      6 – disconnect
      With other modules, like the RN4870, you could use advertisements. This would allow you to read data without making a connection.

  43. Hi Martyn. Great post, Thanks.
    I have been using hm-10 modules with firmware v540 for a long time with no problem. Recently I bought some modules with firmware v604 and all seem not to be able to wake through uart. Meaning, when I send a long text the module used to respond ok+wake and then I was able to send other at commands. Now the long text does not seem to return anything and the module stays in sleep mode. I downgraded to firmware v540 successfully but then the module was not discoverable in role0 and did not discover any other devices in role1.
    Have you noticed this behaviour? Do you have any idea how to resolve this? I saw in a comment above that there is a 605 firmware. Where can I find this? I did not see it in Jinan Huamao website.

    Thanks a lot!

    • I haven’t but I haven’t really used the HM-10s for a while. Contact Jinan Huamao support. I have found them quite helpful. Bare in mind that English is not their first language so keep the questions as clear and short as possible.

  44. Hi Martin, It’s a very helpful post.
    Is it possible to connect an hm10 as master to multiple hm10 slaves like a star or mesh network?

      • Hi, Martin I am using arduino uno as USB to TTL Converter (by grounding RESET Pin of Arduino) for entering AT Commands. So, how to implement this (connect read and disconnect)

  45. Hi, thanks for this very detailed and useful tutorial.
    I can’t get READ property working in BLE Scanner APP. Garbage characters are always read: “_@9″.
    How can I set the value of a READ property in HM10?
    I tried sending chars on UART and then pressing R in Ble scanner, but the same “_@9″ always appears.
    Thanks a lot,


  46. Hi all,
    I tried AT+SLEEP in HM10. Led is switched OFF, but the module is still visible by BLE Scanner and connection can be established.
    Is this the right behaviour? I expected the module to be switched off on Bluetooth.

  47. After more tests.

    – The value 0x7c010a5f4a39 is always reported to the APP when a read is attempted.
    – If Notification is enabled in the APP, bytes sent by the device are correctly reported by the APP.

    As reported in the “Product Parameters”, READ characteristic is not mentioned:

    “Characteristic: Notify and Write (Modifiable use AT+UUID command)”

    Is READ characteristic really supported?



Leave a Reply

Your email address will not be published. Required fields are marked *

eight − = 0

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>