Как получить актуальное время от GSM модуля, даже если оператор его не дает

Ниже, под катом, мой путь решения этой нелегкой (как оказалось) задачи.
Сразу скажу, что в странах без летнего/зимнего времени все гораздо проще.

Понадобилось мне в системе с МК и GSM-модулем SIM800L иметь более-менее точное время.
Плодить лишние сущности в виде микросхемы часов RTC (и работы с ней) не хотелось.
Решено было воспользоваться встроеными возможностями GSM-модуля.
В ходе решения задачи было найдено аж 4 способа решения:

Способ №1 — воспользоваться SIM800 Series_GSM Location_Application Note_V1.01
Посылаем следующую последовательность команд:
AT+SAPBR=3,1,«CONTYPE»,«GPRS» // Set bearer parameter
AT+SAPBR=3,1,«APN»,«internet» // Set bearer context
AT+SAPBR=1,1 // Active bearer context
После чего делаем запрос
AT+CLBS=4,1 // Get longitude latitude and date time
Способ у меня не заработал, после запроса модуль все время долго тупил, и в конце концов изрыгал +CLBS: 2, где 2, согласно этого Application Note — Time Out Error
Продолжив поиски, я нашел

Способ №2 — воспользоваться разделом AT Commands for GSM Location Application документа SIM800_AT_Command_v1_10
Начало точно такое же, как у первого способа:
AT+SAPBR=3,1,«CONTYPE»,«GPRS» // Set bearer parameter
AT+SAPBR=3,1,«APN»,«internet» // Set bearer context
AT+SAPBR=1,1 // Active bearer context
После чего делаем запрос
AT+CIPGSMLOC=2,1 // Get GSM time and date
Способ заработал, хотя меня не все устроило. В 8 с копейками часов вечера модуль вернул мне +CIPGSMLOC: 0,2018/10/27,17:16:29, что указывало на то, что время возвращается «по гринвичу».
Меня это конечно очень «обрадовало», ведь у меня есть летнее/зимнее время, и в зависимости от даты я должен был прибавлять +2/+3 часа (и писать для вычисления значение прибавки отдельную функцию).
В добавок ко всему надо было постоянно держать «Active bearer context» для возможности обновлять показания времени.
А у меня конечный автомат работы с GSM-модулем построен так, что если приходит несколько ошибок, модуль ресетится, и при этом понятное дело происходит Deactivate bearer context.
Полон надежд и ожиданий я взялся за

Способ №3 — воспользоваться командой AT+CCLK.
Просто посылаем AT+CCLK? и модуль возвращает текещую время и дату оператора.
Команда отработала как по маслу, и я уведел долгожанное +CCLK: «18/10/27,20:54:13+12»
К тому же этот способ не зависел от перезапуска модуля (не нужно никаких предварительных настроек перед запросом времени), и в этом его неоспоримый +.
Все было прекрасно, и я сразу заподозрил неладное и вставил карточку другого оператора.
И тут меня ждал ОБЛОМ, модуль каждый раз упорно возвращал ответ вида +CCLK: «04/01/01,00:00:58+12», то есть 1 день 1 месяца 2004 года и время от старта модуля.
Ага, подумал я, этот оператор бука, не дает время, попробуем третьего. Но третий тоже решил, что время, это слишком ненужная пользователю фича, и повторил поведение второго.
Я погуглил, и нашел, что надо включить Get Local Timestamp командой AT+CLTS=1 (и даже нашел ролик какого-то индуса, который показал, как у него исправилась точно такая же ситуация после включения этой опции).
Но увы, у меня все осталось по прежнему. Прибор должен поддерживать карточки всех 3 операторов, поэтому оставалось либо воспользоватся способом №2,
либо воспользоваться предложениями операторов (услуга «Точное время» и пр., у каждого оператора свое название, но суть одна — делаем USSD-запрос, и получаем назад время в PDU-формате/ гори он в аду, причем там только пару первых запросов бесплатны, потом гони бабло за каждый),
либо изобрести свой путь…

Способ №4 — воспользоваться SIM800+Series_NTP_Application Note_V1.01
То есть взять время с NTP-сервера. Но не просто так, а немного «поумничав».
Дело в том, что стандартный способ из этого Application Note выглядит почти как Способ №2
AT+SAPBR=3,1,«CONTYPE»,«GPRS» // Set bearer parameter
AT+SAPBR=3,1,«APN»,«internet» // Set bearer context
AT+SAPBR=1,1 // Active bearer context
После чего «конектимся» к серверу
AT+CNTP=«имя_сервера»,<часовой пояс*4>
После чего делаем запрос
AT+CNTP, на который сервер отвечает +CNTP: 1 (1 означает что синхронизация времени прошла успешно).
После чего можно делать Deactivate bearer context, и даже перезагружать модуль (без сброса питания естественно), время будет исправно тикать дальше — AT+CCLK? возращает номальное время.
Если модуль вернул не 1, значит что-то пошло не так. У меня кроме 1 бывало возвращало 64 — service response error, но достаточно редко.
Как видим, чтобы узнать время, надо опять же знать часовой пояс. Мы то его знаем. Но серверу то пох на наше летнее/зимнее время, он всегда возращает одно и то же. Опять писать код для вычисления «нужного» часового пояса…
Но тут, на выходных, как раз прошла смена времени на зимнее, и я при очередных экспериментах с карточками обратил внимание, что 2 жлобских оператора на запрос AT+CCLK? стали возвращать не +12 в конце (часовой пояс), а +08. То есть ЧАСОВОЙ ПОЯС ОНИ КОРРЕКТИРОВАЛИ в зависимости от зимнего/летнего времени.
И тут меня осенило!!!
Сперва делаем запрос AT+CCLK?, и независимо от того, актуальное время или нет, мы получаем РАБОЧИЙ ЧАСОВОЙ ПОЯС. Затем нужно проанализировать год, и если он начинается на 0 (2004 представлен как 04), значит оператор жлоб, и нужно сделать коннект к NTP-серверу с указанием «актуального» часового пояса. И сервер вернет «актуальное» для нас время.
И оно не будет сбиватся при при перезапуске модуля, и его всегда можно будет узнать командой AT+CCLK?.. Ура, товарищи, всем добра.
  • +3
  • 29 октября 2018, 01:18
  • Gnusmas

Комментарии (10)

RSS свернуть / развернуть
И в результате появились часы в микроволновке?
0
Нет. В результате я знаю, как узнавать время посредством модуля SIMCOM.
0
Мне не понятно, зачем эти приседания с бубном насчёт получения именно местного времени? Получили UTC и отлично. Вычислить местное время и дейлайт оффсет не так уж много кода нужно. К тому же, в Европе этот долбоебизм с переводом часов уже отменили, слава яйцам.
0
Не так уж много, НО НУЖНО. А тут всего 1 лишняя команда модулю. Зачем писать ЛИШНИЙ код, если можно обойтись без него благодаря более продуманному алгоритму.
Ну и в заголовке я написал, что «без летнего/зимнего времени все гораздо проще», у меня же оно, увы, пока действует.
0
Так в Украине скорее всего отменят летнее время, как в ЕС. В любом случае, решать Вам. А за информацию спасибо, добавлю в закладки (вдруг пригодится).
0
Зачем писать ЛИШНИЙ код, если можно обойтись без него благодаря более продуманному алгоритму.
Полагаться на то, что оператор не прислав время пришлет правильный оффсет — выглядит не слишком надежно.
Ну и анализ «если начинается с нуля» вызывает определенные ассоциации :D
0
С первым согласен, а вот про второе не понял.
0
Намек на Y2K bug.
0
Пока еще не отменили. Европа пока в раздумьях, как поступить, и что делать?
0
Вроде как решение принято. Весной некоторые страны перведут в последний раз и так и оставят, некоторые не будут совсем перводить. То есть до весны всем нужно определиться с часовым поясом.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.