Недавно получил свой заказ с новой логической платой от Sensor Watch для вездесущих классических часов Casio F-91W. Модель F-91W не требует представления. Это наверняка самые популярные кварцевые часы в мире, которых в общей сложности было продано около 90 миллионов.

В купленной мной плате Sensor Watch оригинальный кварцевый механизм F-91W заменён новым мозгом на базе ARM Cortex M0+. В ней используются оригинальный ЖК-дисплей, толкатели для кнопок и пьезодинамик. Эта программируемая плата, и проект Sensor Watch также предоставляет простой в плане модификаций набор циферблатов и небольшие дополнительные приложения.

В устройстве нет Bluetooth, но комбинация легковесного, проверенного временем корпуса с долгоживущей батареей и функциональностью, которую без проблем можно воссоздать дома, на удивление великолепна. Где-то за час я смог: заменить плату, настроить двухфакторную аутентификацию (2FA) для своих аккаунтов Google и GitHub, чтобы получать наиболее часто используемые OTP-коды прямо на своё запястье, и написать циферблат-счётчик, который можно использовать для отсчёта шагов или взмахов при гребле на лодке.

Хакать такой девайс — одно удовольствие. Причём для него есть даже эмулятор на основе WASM, который упрощает тестирование на ПК и позволяет поиграться с различными кастомными сборками, например, с моей (в оригинале статьи доступна интерактивная версия часов, — прим. пер.):


Нажмите MODE один раз, чтобы перейти на экран 2FA-токенов. Сейчас ALARM выполняет переключение между токенами Google и GitHub. Не беспокойтесь, я заменил свои реальные секреты TOTP фиктивными значениями. Нажмите ещё раз MODE, чтобы перейти на разработанный мной циферблат со счётчиком. Теперь периодически нажимайте ALARM, чтобы измерять частоту в минуту или иной интересующий вас показатель. Среди прочих циферблатов в этой сборке присутствуют мировые часы, калькулятор времени восходов/закатов, индикатор лунных фаз, показания температурного датчика в реальном времени, установщик формата 24h и режим настройки даты/времени. В дереве исходного кода movement репозитория Sensor Watch есть и много других крутых циферблатов, включая тонометр и модель Солнечной системы.

Весь процесс апгрейда модуля F-91W хорошо описан в блоге Джона Грэхама-Камминга — я даже заказал один экземпляр его крутых оранжевых часов, чтобы переставить туда новую плату.
Ниже я поделюсь о том, как перенести ваши секреты TOTP в сборку, и расскажу о своей разработке нового циферблата.

Циферблат TOTP


Этот циферблат генерирует одноразовые пароли с привязкой ко времени (двухфакторные коды аутентификации), позволяя безопасно авторизовываться на многих популярных сайтах (например, Google и GitHub). Механизм TOTP (time-based one-time password) представляет собой алгоритм, который генерирует одноразовый пароль (OTP), обеспечивая его уникальность на основе текущего времени.

Нажмите кнопку ALARM для переключения между настроенными сайтами/секретами TOTP.
Этот циферблат поддерживает несколько секретов сайтов, которые нужно извлекать из QR-кодов TOTP и добавлять в его исходный код следующим образом:

  1. Получать секрет TOTP или QR-код от сайта, для которого требуется сгенерировать коды.
  2. Если у вас есть только QR-код, сайт Штефана Сандина позволит извлечь его секрет в кодировке Base32 — это будет буквенно-цифровая строка из примерно 32 символов.
  3. Для добавления полученного секрета в код циферблата нужно преобразовать его в шестнадцатеричные байты. Сделать это можно на сайте cryptii.com. Обратите внимание, что TOTP-секрет нужно вводить в верхнем регистре.
  4. Наконец, вам нужно взять полученные шестнадцатеричные байты, добавить их в исходный код циферблата TOTP и заново скомпилировать movement:

▍ Редактирование totp_face.c


Вы можете решить удалить демо-ключи. Предположим, вы захотите добавить ключ в конец списка. В таком случае прибавьте единицу к числу в этой строке:

static const uint8_t num_keys = 2;

Добавьте шестнадцатеричные байты, полученные на шаге 3, в конец этого массива, разделив их запятыми и указав в начале каждого 0x.

static uint8_t keys[] = {
   // Добавьте шестнадцатеричные байты ключа
};

Добавьте в конец этого массива размер секрета (количество только что внесённых шестнадцатеричных байтов):

static const uint8_t key_sizes[] = {

Добавьте ещё одну запись 30 в конец этого массива.

static const uint32_t timesteps[] = {

Добавьте метку для секрета. Например, если он относится к аккаунту Google, можете указать в качестве неё символы { 'g', 'o' }.

static const char labels[][2] = {

Вот и всё — наслаждайтесь всеми удобствами кодов TOTP на своём запястье!

▍ Написание собственного циферблата-счётчика


Весь код находится в этом пул-реквесте, который я отправил в основной проект.

Написать эту функциональность оказалось, на удивление, легко — практически вся реализация уместилась в одной основной функции.

bool ratemeter_face_loop(movement_event_t event,
                         movement_settings_t *settings,
                         void *context) {
    (void) settings;
    ratemeter_state_t *ratemeter_state = (ratemeter_state_t *)context;
    char buf[14];

Эта функция обрабатывает все нужные вам события нажатий кнопок, а также каждый тик часов.

    switch (event.event_type) {

При этом, если вас интересует измерение промежутков времени, обработка анимаций или нечто аналогичное, то циферблат может запрашивать частоту тактов.

В дереве movement присутствует вспомогательная функция watch_display_string, которая как умеет старается отрисовывать буквенно-цифровую строку для различных элементов дисплея Casio, состоящих из 7 и более сегментов. При попытке вывести на эту ограниченную поверхность произвольные строки возникают всяческие проблемы, но всё это достаточно хорошо описано в документации.

Итак, перечислю все состояния часов, которые нас интересуют.

При активации циферблата в индикаторе дней отображается RA.

        case EVENT_ACTIVATE:
            watch_display_string("ra          ", 0);
            break;

При нажатии MODE происходит переключение на следующий циферблат.

        case EVENT_MODE_BUTTON_UP:
            movement_move_to_next_face();
            break;

При нажатии LIGHT включается подсветка.

        case EVENT_LIGHT_BUTTON_DOWN:
            movement_illuminate_led();
            break;

А теперь самое важное… При нажатии ALARM:

  1. Обновляется вычисленная частота на основе промежутка между текущим нажатием кнопки и предыдущим.
  2. Сбрасывается счётчик тактов (часть специального состояния циферблата, который я написал).
  3. Сбрасывается частота быстрых тактов (эта константа определена как 1/16 секунды).

case EVENT_ALARM_BUTTON_DOWN:
            if (ratemeter_state->ticks != 0) {
                ratemeter_state->rate =
                    (int16_t)(60.0 / 
                        ((float)ratemeter_state->ticks /
                         (float)RATEMETER_FACE_FREQUENCY));
            }
            ratemeter_state->ticks = 0;
            movement_request_tick_frequency(RATEMETER_FACE_FREQUENCY);
            break;

И, наконец, при каждом тике… Обновляется дисплей, отображая текущую частоту или «Hi», если частота больше 500/минуту, либо «Lo», если она составляет 1/минуту. При этом также инкрементируется счётчик тактов.

       case EVENT_TICK:
            if (ratemeter_state->rate == 0) {
                watch_display_string("ra          ", 0);
            } else {
                if (ratemeter_state->rate > 500) {
                    watch_display_string("ra      Hi", 0);
                } else if (ratemeter_state->rate < 1) {
                    watch_display_string("ra      Lo", 0);
                } else {
                    sprintf(buf, "ra  %-3d pn", ratemeter_state->rate);
                    watch_display_string(buf, 0);
                }
            }
            ratemeter_state->ticks++;
            break;

Вот и всё! Проект получился проще и интереснее, чем я ожидал.

Если вам понравился этот апгрейд, можете тоже заказать себе плату Sensor Watch с Oddly Specific Objects. Я с ними никак не аффилирован, просто считаю, что Джо реализовал действительно крутую идею.

Telegram-канал со скидками, розыгрышами призов и новостями IT ?

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


  1. hw_store
    09.08.2024 13:29
    +3

    Во-первых, часы на картинке - левые (что не очень важно, т.к. плата от них не используется... но корпус может оказаться не водонепроницаемым)
    Во-вторых, не понятно, как вот этот код туда заносить
    В-третьих, автор почему-то не упоминает, каково время жизни системы от батарейки.
    А так-то да, забавная штуковина.


    1. encyclopedist
      09.08.2024 13:29
      +1

      Не автор, но после посещения ссылок:

      Во-вторых, не понятно, как вот этот код туда заносить

      На плате micro-USB

      В-третьих, автор почему-то не упоминает, каково время жизни системы от батарейки.

      Обещают год


  1. Dynasaur
    09.08.2024 13:29
    +1

    видимо, если эту плату продавать в своих часах, это нафиг никому не нужно. А так, может, и найдутся гики раскурочить старые часы и вставить плату а потом думать - а нафига?


  1. vagon333
    09.08.2024 13:29

    Использую эту модель часов десятки лет: для походов на море самое то.
    Наверное глупый вопрос, но зачем усложнять?
    Если только не нужна какая-то секретность для хранения OTP генератора, почему для OTP не использовать smart watch?


  1. nixtonixto
    09.08.2024 13:29
    +2

    Цифровой подстройки точности хода так и не добавили. Наверное, никому из разработчиков не мешают вечно спешащие или отстающие часы. Датчик температуры, показывающий нечто среднее между температурой руки и температурой воздуха - есть, более нужный датчик давления (помогающий предсказать погоду на ближайшие часы) добавить не догадались... Сколько будильников, есть ли среди них недельные и месячные - для напоминания о еженедельных или ежемесячных событий?


  1. Didimus
    09.08.2024 13:29
    +1

    А если больше трёх-четырёх сервисов и некоторые редко используются, заколебешься переключать...


  1. alcotel
    09.08.2024 13:29
    +1

    1. Если у вас есть только QR-код, сайт Штефана Сандина позволит извлечь его секрет ...

    2. Для добавления полученного секрета в код циферблата нужно преобразовать его в шестнадцатеричные байты. Сделать это можно на сайте cryptii.com...

    "Это ты, Чебурашка, здорово придумал!" - пропускать свои секретики через пару левых сайтов. Не поверю, что на том же питоне нет либ, работающих локально.


    1. vvzvlad
      09.08.2024 13:29

      А кому нужен ваш секрет непонятно от какого именно сервиса и логина? Это же как пин-код от банковской карты ввести.


  1. xSVPx
    09.08.2024 13:29

    Ну т.е. любой нашедший ваши часы....

    Нет, так безопасность не увеличивается...

    Наверное, можно допилить до состояния "введите пин", но как-то я сомневаюсь, что это год проработает. Тотр вообще-то требует еще и довольно точного времени...


    1. SagePtr
      09.08.2024 13:29

      Любой нашедший не знает ни логина-пароля владельца часов, ни какому сервису код принадлежит