Как получить актуальное время от 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

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

RSS свернуть / развернуть
И в результате появились часы в микроволновке?
0
Нет. В результате я знаю, как узнавать время посредством модуля SIMCOM.
0
Мне не понятно, зачем эти приседания с бубном насчёт получения именно местного времени? Получили UTC и отлично. Вычислить местное время и дейлайт оффсет не так уж много кода нужно. К тому же, в Европе этот долбоебизм с переводом часов уже отменили, слава яйцам.
0
Не так уж много, НО НУЖНО. А тут всего 1 лишняя команда модулю. Зачем писать ЛИШНИЙ код, если можно обойтись без него благодаря более продуманному алгоритму.
Ну и в заголовке я написал, что «без летнего/зимнего времени все гораздо проще», у меня же оно, увы, пока действует.
0
Так в Украине скорее всего отменят летнее время, как в ЕС. В любом случае, решать Вам. А за информацию спасибо, добавлю в закладки (вдруг пригодится).
0
Зачем писать ЛИШНИЙ код, если можно обойтись без него благодаря более продуманному алгоритму.
Полагаться на то, что оператор не прислав время пришлет правильный оффсет — выглядит не слишком надежно.
Ну и анализ «если начинается с нуля» вызывает определенные ассоциации :D
0
С первым согласен, а вот про второе не понял.
0
Намек на Y2K bug.
0
Пока еще не отменили. Европа пока в раздумьях, как поступить, и что делать?
0
Вроде как решение принято. Весной некоторые страны перведут в последний раз и так и оставят, некоторые не будут совсем перводить. То есть до весны всем нужно определиться с часовым поясом.
0
В Германии с какого-то момента многие провайдеры перестали сообщать время через «AT+CCLK?». Спасибо за статью: очень помогло перенастроить систему на SIM800C! Однако, у меня (согласно пункту 4 статьи) после «AT+CNTP» и получения на это действительно актуального времени как ответ (в виде +CNTP: 1,«21/10/22,13:59:45»), внутренние часы SIM800C не синхронизируются, и «AT+CCLK?» по-прежнему возвращает фактически 00/01/01 и время с момента подачи питания.

Время в системе я веду в UTC, так как еще давно написал библиотеку, которая настраивается и учитывает зоны и переход на летнее/зимнее время для Европы, если надо показать время на индикаторе или корректировать по «наручным» часам. Кстати, хотя после всеевропейского референдума по поводу летнего времени, когда народ высказался «против», фактически переход все еще не отменили, т.к. не погут договориться, на каком времени остаться, и всем ли странам делать одинаково или таки каждая решит для себя, на каком времени оставаться. Так что вот в октябре в Германии переводим на зимнее и надеемся (в который уже раз), что весной будет последний переход.

Это все цветочки, однако, в сравнении с полной неразберихой с этим в мире или даже в отдельной стране! Я тут как раз занимаюсь модернизацией часов на Дюссельдорфской Телебашне (https://ru.wikipedia.org/wiki/Rheinturm, и те световые часы на ней, — технически мой проект с коллегой), там внутри есть еще круговое зеркало с мировой картой и временем в 16-ти значимых городах. Так вот, в США есть Гтаты и даже отдельные города, которые либо херят переход вообще, либо делают его по своему графику. К счастью, интересующие меня города Штатов на карте ведут себя прилично (но не так, как в Европе). Особая заморочка с Тегераном: те ребята живут по исламскому календарю и переходят с плавающим графиком (+-2 дня в марте и сентябре). Системы я не узрел и забил таблицу до 2050, после чего либо шах, либо ишак, либо Иран… Хорош, что на карте нет города из Марокко типа Касабланки: те ребята возвращаются на зимнее время на период Рамадана (если он упал на летнее время), который, как известно, плавает по году из-за привязки к Луне. Полный атас…
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.