The next feature of working with the controller is that in one reading cycle you can get only 12 events, 8 bytes each. And for each passage of a person into the office, two events are already generated:

1) a key is found in the key bank (the key bank is another block in the distributed memory of the controller);

2) the passage took place (if, of course, it took place).

Below is a C++ code snippet that implements the single buffer read loop method.

bool SerialPortInlet::readBufferCycle(unsigned short& bottom, unsigned short const& top, unsigned char& u_lowerBound,
unsigned char& l_lowerBound, std::vector& readBuffer, std::string& result)
// Count bytes to be read
unsigned short byteCountTmp = top - bottom;
BOOST_LOG_SEV(log_, logging::info) << "Need read " << byteCountTmp << " byte"; unsigned char byteCount; // Can't read more than 12 events in one cycle (96 bytes) byteCount = byteCountTmp > 0x60 ? 0x60 : (unsigned char)byteCountTmp;
BOOST_LOG_SEV(log_, logging::info) << "Read " << +byteCount << " byte"; // Describing the body of the command std::vector body = {0x02, 0xA0, byteCount, u_lowerBound, l_lowerBound}; std::vector command; // Get the full text of the command generateComplexCommand(command, Command::BYTE_CODE_READ, body); // If for some reason it was not possible to send the command (for example, the end device is not connected), false is returned if (!sendCommand(command, result)) { return false; } // Otherwise, we send the response from the device to parsing by events SerialPortType::Answer answerEvents; if(!Parsers::parserAnswer(log_, result, answerEvents, Command::BYTE_CODE_READ)) { BOOST_LOG_SEV(log_, logging::error) << "Failed parse buffer reading"; return false; } readBuffer.insert(readBuffer.end(), answerEvents.body.begin(), answerEvents.body.end()); // Shift the bottom of the buffer to read the next events bottom = bottom + byteCount; u_lowerBound = (unsigned char)(bottom >> 8) ;
l_lowerBound = (unsigned char)bottom;
return true;

It added a little trouble that, finally pulling out the necessary bytes, in place of the card information, we saw not the card number, but the address at which it is located. Therefore, then each key number has to be read separately at the address. We also did not immediately notice the presence of bytestaffing, we introduced its processing after the first test with the board.

The complete block diagram of the developed system looks like this.

It was very convenient to check the performance of all devices using the СuteCom graphical serial terminal. After successful testing, the program was set to autorun, and Raspberry went to live on the ceiling next to the ACS board.

Working on the Rightech IoT Cloud platform
The main data from the controller are events, they come to the platform in JSON format and include the following fields:

eventTime – event start time;
eventCode – event code;
keyNumber – employee’s card number (the field can be empty if the event was not triggered by a card).
The device model looks like this.

Possible events:

the call button is pressed;
unidentified key at the entrance;
unidentified key at the exit;
the key was found in the key bank at the entrance;
key found in key bank upon exit;
opening by the operator over the network;
the door is locked by the operator;
the door is left open after entering;
door left open after exit;
passage took place at the entrance;
passage took place on the way out;
controller reboot.
An object

The interface of the object is completely formed according to the developed model.

Hurray, now, having gathered in the office kitchen waiting for a pizza for the holiday, you can not go anywhere, but simply open the mobile application and press the button to open the door for the courier!


You can see that there is a command not only to read the event buffer, but also to write new boundaries. The buffer boundaries are stored in the controller’s memory – the beginning and the end. When a read command arrives at the device, these boundaries are taken from memory and reading from the event buffer takes place within them. The end buffer boundary is shifted automatically on the controller when new events are received. But the initial boundary of the buffer must be overwritten (indicating the final boundary after the last reading) so as not to read the same data again. But this needs to be done only after the event data has been successfully sent to the platform.

It is convenient to fix the successful receipt of data and then send a command to overwrite the initial boundary in the machine.

Here you can see the cycle – – (now events are read every 30 seconds).

In the “Read events” state, we read new events.

In the “Clear buffer” state, we write a new border.

In the “Await timer …” state, we are waiting for the start of a new cycle.

There are also additional feedbacks for states in which commands are sent. If during the operation of the timer there was no successful execution of the command, the timer is triggered and a corresponding message is sent to the operator, after which the command is resent.

Further use of collected data

This project has found its continuation in integration with our internal CRM system, in which the employee information tab always shows up-to-date information about who is or is not in the office.

The time of entry / exit from the office is also displayed, the total number of hours per month is considered.

The Slack messenger says every day that the office is open when the first person arrives, taking the keys at the reception.

Data is collected from the platform using the REST API. The platform API provides the ability to work, interact and use the platform entities and their data in such external systems as web portals, mobile and web applications or, as in our case, CRM systems.

Now we know a little more about how ACS can work in IoT projects. In the following materials, we will consider how to calculate the number of people in the office based on the information received and what practical applications this idea has.

Leave a Reply

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