Blog

ブログ

【shopify】初回のみ表示するポップアップ

個人情報同意などに使える、サイト内のどのページからでも初回だけ表示されるポップアップを作りたいと思います。
全ページなのでtheme.liquidに直接書く方法もあると思いますが、簡単に管理できるように新規セクションで作成してみます。

セクションを新規作成

カスタマイズボタンの横にある3点ボタンから、「コードを編集」を開きます。
sections>「新しいセクションを追加する」で空のセクションを作成します。

liquid編集

まず、jquaryを読み込ませます。CDNまたはassetsに必要なファイルを入れて読み込んでください。
次にCSSを追加します。このセクション内だけに適用されればいいので直接書いちゃいます。

{%- style -%}
  .popup {
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.6);
    position: fixed;
    z-index: 1001;
    top: 0;
    left: 0;
  }
  .popup-content {
    width: 75vw;
    max-width: 750px;
    height: 40vh;
    background: white;
    border-radius: 4px;
    padding: 3rem;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    margin: auto;
  }
  .close-btn {
    background-color: black;
    border-radius: 2px;
    color: white;
    text-align: center;
    cursor: pointer;
    font-size: 1.2rem;
    padding: 1rem 2rem;
    display: block;
    max-width: 10rem;
    margin: 1rem auto;
    width: 100%;
  }
  .close-btn:hover, 
  .close-btn:focus {
      text-decoration: none;
      cursor: pointer;
      opacity: 0.8;
  }
  @media screen and (max-width: 768px){
    .popup-content{
      width: 80vw;
    }
  }
{%- endstyle -%}

そしてポップアップ本体です。

<div id="popup" class="popup">
  <div class="popup-content">
    <div>{{ section.settings.popup_text }}</div>
    <span class="close-btn">はい</span>
  </div>
</div>

今回は、localStorageでユーザーが訪問済みなのか否か判断させます。さらに「はい」のボタンクリックによって、visitedtrueになるようにしました。

<script>
  const keyName = 'visited';
  const keyValue = true;
  if (!localStorage.getItem(keyName)) {
      $('#popup').css('display', 'block');
      $('.close-btn').click(function(){
          $('#popup').css('display', 'none');
          localStorage.setItem(keyName, keyValue);
      });
  } else {
      $('#popup').css('display', 'none');
  }
</script>

最後にスキーマです。表示されるテキストはカスタマイズ画面から編集できるようにリッチテキストにします。これで改行や太字、リンクもできるので便利です。

{% schema %}
{
  "name": "ポップアップ",
  "class": "pop-section",
  "settings": [
    {
      "type": "richtext",
      "id": "popup_text",
      "label": "テキスト"
    }
  ],
  "presets": [
    {
      "name": "ポップアップ"
    }
  ]
}
{% endschema %}

セクションを設置

あとはカスタマイズ画面でセクションを差し込めば完成です。
特定のページのみであればテンプレートごとに設置しますが、全ページに適用したいので共通のヘッダー内に入れました。

このようなセクションが1つできれば、Cookieにしたり、販促案内やクーポン用にカスタマイズの幅が広がりそうです。

参考:https://into-the-program.com/execution-firsttime-access/

使用テーマ:Dawn 15.1.0

【shopify】ヘッダーのハンバーガーメニューの配置を変更したい

テーマのデフォルトでは左側にハンバーガーメニューが配置されているけど、右側に置きたい。。
しかし、カスタマイズ画面ではロゴの配置くらいしか設定できない。。
ということで、今回はshopifyのDawnテーマ(15.1.0)でできるだけ簡単に実装したいと思います。

liquidで物理的に動かしてみる

そもそもヘッダーセクションではソースコードの兄弟要素が「ハンバーガーメニュー・ロゴ・アイコン」という順番で書かれているため、header.liquid内の該当箇所を入れ替えてみました。

ソースコード上は理想の順番になりました。
しかしブラウザを確認しても、あれ、変わりません。。

 

CSSをチェック

ヘッダーセクションの中身が大きく3つに分かれており、flexで並べられています。
base.cssで順番が指定されていました。navigationを一番右に移動させます。

CSSだけでハンバーガーメニューの位置を変更できました!
でも開閉が左のままで不自然なので調整が必要みたいです。

 

Base.css

.menu-drawerに以下を追加

transform: translateX(100%);
left: auto;
right: 0;

 

component-menu-drawer.css

.js details[open].menu-opening>.menu-drawerに以下を追加

transform: translateX(0%);

 

 

配置も挙動も理想の動きになりました。

Liquidファイルを編集しなくても、CSSで簡単にカスタマイズできることがわかりました。

 

参考:

・CSS: カスケーディングスタイルシート[justify-self]

https://developer.mozilla.org/ja/docs/Web/CSS/justify-self

・shopifyコミュニティ「Re: モバイル表示のハンバーガーメニュー位置を右に表示したい。(テーマ:Spotlight)」

https://community.shopify.com/c/%E6%8A%80%E8%A1%93%E7%9A%84%E3%81%AAq-a/%E3%83%A2%E3%83%90%E3%82%A4%E3%83%AB%E8%A1%A8%E7%A4%BA%E3%81%AE%E3%83%8F%E3%83%B3%E3%83%90%E3%83%BC%E3%82%AC%E3%83%BC%E3%83%A1%E3%83%8B%E3%83%A5%E3%83%BC%E4%BD%8D%E7%BD%AE%E3%82%92%E5%8F%B3%E3%81%AB%E8%A1%A8%E7%A4%BA%E3%81%97%E3%81%9F%E3%81%84-%E3%83%86%E3%83%BC%E3%83%9E-spotlight/m-p/2646855

LINQ の基本を理解しよう

LINQ とは

LINQ とは コレクション・XML・SQLなど様々なデータソースに対する検索・操作を行うもので、System.Linq を参照することにより提供される拡張メソッド群(標準クエリ演算子)ことを指します。
本稿では特に利用する機会の多いコレクション(IEnumeable)に対する LINQ to Object の解説を行います。

メソッド構文とクエリ構文

LINQ は拡張メソッドで提供されることから、当然コレクションのメソッドとして利用する(メソッド構文)ことが可能です。
また一部の標準クエリ演算子に対しては言語仕様としてキーワードが割り当てられており、それを用いることでSQLライクに記述する(クエリ構文)ことも可能です。

例)メソッド構文とクエリ構文
 ※本稿のサンプルコードではメソッドの引数としてラムダ式を使用します。

var source = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

// いずれも結果で得られるコレクションの型はIEnumerable<int>となり、
// 列挙することで { 1, 2, 3, 4, 5 } の結果(要素)を得ることができます。

// メソッド構文
// 処理しない値を取り出す場合はSelectを書略可能
var methodResult = source.Where(x => x <= 5);

// クエリ構文
// クエリ構文ではselectを省略不可
var queryResult =
    from x in source
    where x <= 5
    select x;

またクエリ構文で記述したコードはコンパイルを通して標準クエリ演算子に変換されますので、最終的に得られる結果は同一になります。
前述のコードから得られる実行形式のファイルを逆コンパイルした結果は下記となります。

// Program
using System.Collections.Generic;
using System.Linq;

private static void <Main>$(string[] args)
{
	int[] source = new int[9] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	IEnumerable<int> methodResult = source.Where((int x) => x <= 5);
	IEnumerable<int> queryResult = source.Where((int x) => x <= 5);
}

なお全ての標準クエリ演算子をクエリ構文で記述することはできないため、それらの機能が必要な場合はメソッド構文で記述する必要があります。
※メソッド構文とクエリ構文を混ぜて使用することも可能ですが、式を分けるかどちらかに統一したほうが可読性の面からも無難です。

基本的な使い方

Where によるデータの抽出と Select によるデータの選択・処理

Where メソッドでは、コレクションから条件に合致する要素を抽出することが可能です。
Select メソッドでは、コレクションの全要素に対して処理を行った結果を取得することができます。
Where メソッドと Select メソッドを組み合わせてコレクションの条件に合致した要素に処理を行った結果を取得する、といった用途で利用することが多いようです。
ここでは、数値のコレクションから条件に合致する要素を抽出し二乗したコレクションを取得する例を示します。

var source = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

// メソッド構文
var methodResult = source.Where(x => x <= 5).Select(x => x * x);

// クエリ構文
var queryResult =
    from x in source
    where x <= 5
    select x * x;

// 結果は { 1, 4, 9, 16, 25 } となる。

また、数値型のコレクションで利用する以外にも、オブジェクトのコレクションに対して処理を行うことも可能です。
例えば人物を定義するPersonクラスのコレクションから20歳以上の人を抽出して氏名をつなげた文字列を取得するといった処理の場合、下記のように書くことができます。
※本稿のサンプルコードではnullチェック等を行っていませんが、実際に利用する場合は例外が発生しないように条件式に気を付けましょう。

/// <summary>
/// 人物を定義するPersonクラス
/// </summary>
class Person
{
    /// <summary>名</summary>
    public string FirstName { get; set; }
    /// <summary>姓</summary>
    public string LastName { get; set; }
    /// <summary>年齢</summary>
    public int Age { get; set; }

    public Person(string firstName, string lastName, int age)
    {
        FirstName = firstName;
        LastName = lastName;
        Age = age;
    }
}

/// <summary>
/// サンプルクラス
/// </summary>
class Sample
{
    static void Main()
    {
        var persons = new[] {
            new Person("Terrance", "Huff", 18),
            new Person("Deven", "Cyrus", 26),
            new Person("Dave", "Corbett", 53),
            new Person("Brion", "Shoebridge", 12),
            new Person("Terence", "Long", 31)
        };

        // メソッド構文
        var methodResult = persons.Where(x => x.Age >= 20).Select(x => $"{x.FirstName} {x.LastName}");

        // クエリ構文
        var queryResult =
            from x in persons
            where x.Age >= 20
            select $"{x.FirstName} {x.LastName}";

        // 結果は { "Deven Cyrus", "Dave Corbett", "Terence Long" } となる。
    }
}

GroupBy によるデータの組み分け

GroupBy メソッドでは、コレクションの要素から取得した値をもとにグルーピングを行い、グループごとにデータを抽出することが可能です。
下記のサンプルコードでは、前述のPersonクラスのコレクションを元にFirstNameの頭文字でグルーピングを行っています。

// メソッド構文
var methodResult = persons.GroupBy(x => x.FirstName[0], x => $"{x.FirstName} {x.LastName}");

// クエリ構文
var queryResult =
    from x in persons
    group $"{x.FirstName} {x.LastName}" by x.FirstName[0];

// 結果は、下記となる。
// Key 'T'
//   { "Terrance Huff", "Terence Long" }
// Key 'D'
//   { "Deven Cyrus", "Dave Corbett" }
// Key 'B'
//   { "Brion Shoebridge" }

OrderBy / OrderByDescending による並び替え

OrderBy メソッドは昇順、OrderByDescending メソッドは降順で、コレクションの要素の並び替えを行います。
クエリ構文の場合は orderby 句と ascending 句または descending 句の組み合わせで並び替える順序を指定します。
数値を降順で並び替える場合は、下記のようなコードになります。

var source = new int[] { 3, 5, 7, 1, 10, 8, 4, 6, 2, 9 };

// メソッド構文
var methodResult = source.OrderByDescending(x => x);

// クエリ構文
var queryResult =
    from x in source
    orderby x descending
    select x;

// 結果は { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 } となる。

最後に

今回は割と利用頻度が高いと思われるメソッドを簡単に説明しましたが、これらを組み合わせることで複雑なデータの抽出処理を可読性を上げつつ簡単に記述することができます。
ただし LINQ は気軽に使える反面、書き方によっては非常に大量のメモリを使うことがあるため、Web アプリケーションのように複数スレッドで同時実行されるようなプログラムで大量のデータを扱う場合は、問題がないか十分気を付ける必要があります。
適切な場所でうまく活用できるようにしましょう。

.NET コーディングのTips2選

初めに

ここ最近携わった案件でいくつか気になるコードを見かけましたので、多少なりとも改善できればとTips的なものを2つまとめてみました。
非常に初歩的な内容のため、今更言われなくても知ってるよ!という方はスルー推奨、初めて聞いた方は今後の参考にしていただければと思います。

foreachステートメント直前の要素数チェック

foreach の直前で要素数の判定を行っているコードを見かけますが、要素数が 0 の場合は何もせずブロックを抜けるため、要素の有無で処理分けが必要なければ判定は不要です。

例1:直前のif文で抜けるパターン

// このif文のブロックは不要
if (elements.Count == 0)
{
    return;
}
foreach (var element in elements)
{
    // 処理本体
}
return;

例2:if分のブロックとして処理するパターン

// このif文の判定は不要
if (elements.Count > 0)
{
    foreach (var element in elements)
    {
        // 処理本体
    }
}

いずれの場合も、 `foreach` のみ記述するだけで問題ありません。

foreach (var element in elements)
{
    // 処理本体
}

IEnumerableを実装するコレクションの要素存在チェック

IEnumerable を実装するコレクションに要素が存在するかどうかをチェックする際、 Count メソッドで取得した結果が 0 より大きいかで判定するコードを見かけますが、このメソッドは対象をカウントするために内部で全要素を列挙しているため、パフォーマンスがかなり悪くなります。
明確な要素数で判定する必要がない場合は Any メソッドを使うようにしましょう。

検証

0 から 999999999 までの数値を列挙したコレクションから 1000000 以上の要素が存在するかどうかを、Count と Any それぞれのメソッドで判定した場合の実行時間を比較します。

コード
using System.Diagnostics;

public class Example
{
    delegate bool CheckFunc(IEnumerable<int> list);

    /// <summary>
    /// 判定結果と処理時間を出力
    /// </summary>
    static void WriteResult(string name, CheckFunc func, IEnumerable<int> list)
    {
        Console.Write($"{name} : ");

        // 時間計測開始
        var sw = new Stopwatch();
        sw.Start();

        if (func(list))
        {
            Console.Write("要素が存在します");
        }
        else
        {
            Console.Write("要素が存在しません");
        }

        // 時間計測終了
        sw.Stop();

        Console.WriteLine($" : {sw.ElapsedMilliseconds} ミリ秒");
    }

    /// <summary>
    /// 0から999999999までの整数を列挙
    /// </summary>
    static IEnumerable<int> GetValues()
    {
        for (var i = 0; i < 1000000000; ++i)
        {
            yield return i;
        }
    }

    public static void Main()
    {
        // コレクションを取得
        var array = GetValues();

        // 拡張メソッドを利用して要素を抽出
        // このコードでは1000000以上の値を抽出
        var result = array.Where(x => x >= 1000000);
        // 次のようにクエリ式で書くことも可能(現場によってはNGかも)
        // var result = from x in array where x >= 1000000 select x;

        // 結果に要素が存在するかどうかを判定
        // Anyメソッドの場合
        WriteResult("Any", x => { return x.Any(); }, result);
        // Countメソッドの場合
        WriteResult("Count", x => { return x.Count() > 0; }, result);
    }
}
実行結果
Any : 要素が存在します : 23 ミリ秒
Count : 要素が存在します : 18756 ミリ秒

処理にかかる時間は環境によって変わりますが、同じ判定結果を得るのにかなりの差が出ることを確認できます。

また、抽出した要素を再利用しない場合はメソッドチェーンで簡潔に書くこともできます。

if (array.Where(x => x >= 1000000).Any()) {
    // 処理
}

簡潔にパフォーマンスを考慮したコードを書くように意識したいですね。

次回は

今回出てきた IEnumerable に関連して LINQ の解説やTipsをまとめてみたいと思います。

EC-CUBEからMysqlへのSSL接続を設定する

お世話になっております。株式会社Joolenの白井です。

いつもOSS開発部にてEC-CUBEのカスタマイズ開発とかをやっています。ときどき本体へのコントリビュ〜ションなどもやっています(もうちょっと増やしたいです)。

そんなに派手なことはやっておりませんので、ちまちました設定の話をします。

Continue reading “EC-CUBEからMysqlへのSSL接続を設定する”

ラズパイ で電子ロッカーを作る!(IoTネットワーク構成編)

今回の記事を担当するエンジニアの榎本です。
これまでの記事

電子ロッカー開発始めます → 電子ロッカー開発に至った経緯など
ラズパイ で電子ロッカーを作る!(物理構成編)→ 機器や配線など物理的な構成に関する記事

ラズパイ で電子ロッカーを作る!(ソフトウェア編)→プログラムについて

ここでは、AWSのEC2インスタンス上(EC-CUBE)で動いている「ご近所マルシェ Joolen」がどのようにして「電子ロッカーを開ける」という制御を行っているのかを説明していきます。

ネットワーク構成

IoT構成図

このようになっています。AWSとラズパイ 間の通信のプロトコルにはMQTTを採用しました。

MQTTは簡単にいうと、データを配信するためのプロトコルです。
「非力なデバイスやネットワークが不安定な場所でも動作しやすいように、メッセージ通信電文が軽量に設計されていることが特徴(Wikipediaより抜粋)」で、ラズパイ のような小さなコンピュータでも難なく扱えます。
Web socketにも似ていて、メッセージがPublish(送信)されると簡単に受けてはそのメッセージを拾うことができます。

AWSからラズパイ へのメッセージングに Web APIを使うことも検討しましたが、IoT機器にはセキュリテイ上、固定IPを持たせたくないという思いもありましたので今回の構成になりました。

今回のマルシェではEC2インスタンス上で、EC-CUBEは動いていますが「ロッカーの鍵を開けて!」というタイミングで メッセージを 送信(Publish)しています。流れとしては下記の通りで、仕組みとしては非常にシンプルなものです。
・解錠用のメッセージをMQTT Broker に対して 送信 (Publish)
・ロッカー(ラズパイ)は、MQTT Brokerのメッセージを監視(Subscribe)。MQTT BrokerへのPublishを検知したら後続の処理を行う。

AWSからラズパイ への通信

さて、ここからが本題です。
MQTTのやりとりをするためのサーバ(MQTT Broker)はAWS IoT Coreを採用しました。このIoT Coreへの接続は証明書を使う必要があります(ドキュメント)。
ラズパイ に 証明書を保存して接続、ということも当然可能ですが、小さなIoT機器にセキュリティ情報となる証明書を入れておくのは最善手とは言えません。

ということでIoT 専用のデータ転送サービスSORACOM Beamを使っての接続を行うことにしました。(SORACOM を使った双方向通信のデザインパターンはSORACOMさんによってまとまっています。)
このサービスは証明書の管理や脆弱性への対応等の煩雑な処理をクラウドにオフロードすることができるので、ラズパイ に証明書を保存する必要はありません。

 

下記の通り、ラズパイ 側ではAWS IoT Coreの認証情報を意識することなく接続することが可能です。

SORACOM Beamは非常に安価(1 リクエスト(*) あたり 0.00099 円)かつ、 1アカウントあたり月間 100,000 リクエストまでの無料枠もあるのでとても使いやすいサービスだと思います!

IoTは特にセキュアな接続を心がけていきたいですね。

ご近所マルシェ Joolen稼働中です!

※現在、アトレ松戸 3Fでご近所マルシェ ジョーレン で購入したものを受け取り可能です!(アトレ松戸での2021/5/23まで)

ありがとうございました。

ラズパイ で電子ロッカーを作る!(ソフトウェア編)

今回の記事を担当するエンジニアの榎本です。

これまでの記事

電子ロッカー開発始めます → 電子ロッカー開発に至った経緯など

ラズパイ で電子ロッカーを作る!(物理構成編)→ 機器や配線など物理的な構成に関する記事

ここからは Raspberry Pi上で動くプログラムについて書いていきます。

今回Raspberry Pi側で採用したプログラム言語について

Node-REDというビジュアルプログラミングツールを採用しました。Node-REDとは何かというと。。。

Node-REDはハードウェアデバイス、APIおよびオンラインサービスを新しく興味深い方法で接続するためのツールです。ブラウザベースのエディタによってパレットに並ぶ多種多様なノードを結びつけて用意にフローを作成でき、さらにシングルクリックで実行環境にデプロイすることができます。

Node-RED日本ユーザー会トップページより引用

とのこと。
つまり、ブラウザからノードと呼ばれるブロックを線でつなげて思い通りにデバイスを動かせる素敵な言語になります。名前から推察できる様に、Node.js上で構築されてますので、必要に応じて Javascriptでのコーディングまでできるので、編集が容易かつ柔軟性が高い言語となっています。

コードエディタはこんな感じ

画面上で「再起動」などと書かれているかボックスがノードとなります。各処理をつなげてやりたいことを実現できます。

電子ロッカーを構成する各種ノードの紹介

Injectノード
上記コードエディタ左側の「timestamp」と書かれているノードです。時間を指定して処理を起動することができます。

Execノード
上記コードエディタで「再起動」と書かれているノードです。このノードでコマンドの実行を行うことができます。この場合は下記のコマンドを実行することで再起動を実現しています。

sudo shutdown -r now

つまり上述2つのノードの組み合わせで、「毎朝7時に再起動をする」という命令が組み立てられます。非常に分かりやすくて便利ですね。

MQTTノード
今回の電子ロッカーは

ECサイトからの命令をAWS IoT CoreのMQTTへPublish

ラズパイ 側で該当のTopicをSubscribeしメッセージの受信をきっかけに鍵を操作

することで解錠・施錠の実行を実現しています。Node-REDはMQTT処理に必要なノードが用意されているので非常に簡単にこの処理を実行することができます。
入力側のmqttが Subscribeで 出力側がPublishになります。
ノードには MQTT Broker となるサーバの情報・トピック・QOS(=Quality Of Service)を設定することで簡単にPublish/Subscribeを実現できます。(見落としがちですが、QOSはPublish側と合わせる様にしましょう!私はここの数値が食い違っていたために数時間ハマりました。。。)

ノードの設定画面
↑↑MQTT Brokerの設定画面↑↑

余談ですがMQTT Brokerは AWS IoT Coreを SORACOM Beam経由で使っています。AWS IoT Coreの認証を肩代わりしてくれるので ラズパイ 側に証明書などを持つ必要がないことがメリットになります。(これはまた後日記事にします)

PCA9685ノード

こちらは標準のノードではないので、パレットの管理から自分で追加する必要があります。Node-REDのホームページにサンプルを含め説明が載っています。

ノードの追加はこの画面から可能です。
PCA9685ノードの編集画面

基本的には
1. PCA9685 Deviceで対象のデバイスを選択(デバイスの設定方法は下記に記述)
2. Channelはターゲットになる PCA 9685 の チャネルを選択 (直接指定でも良いし、msg.channel という変数に設定した数値でも良い)
3. Unitはサーボモータを動かしたいときは、「microseconds」 LEDを点灯させたりしたいときは「Percent」を選択しましょう。

デバイスの設定画面

PCA9685を指定する画面です。ラズパイ 側で下記の通りになっていれば特に変更する必要はありません。
※Addressは下記の画面で 0x40(=64)であることが確認できます。

例) 15個の扉の解錠を行い、操作がされた時にLEDを点滅させるためのフローは下記の様になります。
1. open_1_all へのメッセージの Publishをトリガーにしてフローが起動
2-1. サーボモータを動かす
  2-1-1. サーボモータを140度回転した位置にするためmsg.payloadに値を設定
  2-1-2. PCA9685 ノードを経由して1〜15チャネルに命令を出す
2-2. LEDを点滅させる
  2-2-1. 0番のチャネルに接続されたLEDを点滅させる
2-3. MQTTメッセージを受け取ったことを送信元のプログラムへ返却するため、受け取ったランダムな文字列をそのまま返却用のMQTTトピックにPublishする

他に大きなポイントとして、ラズパイ の死活監視に使っているlwm2ノードがあるのですが、これは監視についての記事で触れたいと思います。

次回は電子ロッカーのネットワークや、利用しているSORACOMのサービスについて触れていきたいと思います!

ラズパイ で電子ロッカーを作る!(物理構成編)

新規事業を担当している榎本です。
前回の記事で、私たちがなぜ電子ロッカーを作るという決定をしたのか記載しました。では早速、ロッカーを動かすための物理的な構成を書いていきます!

全体図

まずは全体図の写真です。かなりシンプルな構成ですね。基本的にECサイトから受け取った「ロッカーの解錠・施錠」に関する命令をラズパイ が受け取って複数のサーボモータに伝達する形で実現しています。

※見やすくするためにサーボモータ などは外した状態で撮影しています。

機器について一つずつ解説していきます。

機器名称役割
Raspberry Pi Zero WH電子ロッカーの心臓部。
内部のソフトウェアは誰でも扱いやすいようにビジュアルプログラミング言語である
Node-REDを採用しました。美味しいものマルシェ(ECサイト)からのロッカー解錠の
命令に従って周辺危機の操作を行っています。
あまり重たい処理は無いためスペックは重視せず、小さくて安価な Zero WHを採用。
AK-020 (Soracom Air)通信は Soracom Air for セルラーを使っています。通信に必要なモデムとしてAK-020を
利用しています。(このモデムの中に SIMが入っています)
Amazonで販売しているSORACOMスターターキットは通信量1,000円分のクーポンも
ついていてお得でした
PCA9685購入者1人につき、1つずつロッカーの扉を割り当てています。それぞれのロッカーの
扉を個別に操作するためにPCA9685を使ってサーボモータを制御しています。
電池ボックスサーボモータを動かすための電源です。プロトタイプでは電池ボックスを
使っていますが、USBからの給電になる予定です。
TowerPro
SG92R
ロッカーを実際に解錠するためのモーターです。扉1つにつき、1つのモーターが
使われます。写真には載せていませんが、PCA9685につなげています。
高輝度
赤色LEDランプ
ロッカーが実際に施錠・解錠されたことをユーザーが認識できるように、操作された
タイミングでLEDを点滅させます。これも写真には載せていませんが、PCA9685に
つなげてます。

配線について

ラズパイ とPCA 9685の配線図です。GPIOは 1,3,5,6 (青枠で囲った部分)を使っています。

ラズパイ のPIN番号ラズパイ側の名称PCA9685側のピンの名称
15V PowerVCC
3SDASDA
5SCLSCL
6GroundGND

実物の写真はこのようなイメージです。PCA9685は基盤にPINの役割が書いてあるので間違えにくいですね。

PCA9685

ちなみに、PCA9685を使うときにはラズパイ 側のコンフィグを変更してI2Cを有効にする必要があります。こちらの手順についての記事は多いので調べればすぐに分かると思いますが、こちらにも掲載しておきます。

sudo raspi-config

こちらを実行すると表示される画面がこちら。ここで5番の Interfacing Optionsを選択して

I2Cを選択

「はい」を選択して I2C interfaceを有効にしておきましょう!

これでラズパイ を通して複数のサーボモータの制御をするための準備は完了です。サーボモーター はこの様な形で扉に取り付けられています。サーボモータが約140°動くことでギアを経由して鍵が閉まり、ロッカーが施錠されている様子がご覧いただけます。

次回はラズパイ の操作に利用しているプログラム言語、Node-REDについてご紹介していきます!

電子ロッカー開発はじめます

今回の記事を担当するエンジニアの榎本です。
トップページにも記載されていますが、松戸の美味しいものマルシェを開催中です!(2021/3/31まで)
ありがたいことに多くのお客様にご利用いただき、めでたく4/23より第2回目の開催も決定しました。

さて、第1回目ではお客様への商品受け渡しを人の手で行っていました。しかし、下記の理由により次回のイベント以降の受け渡しは無人で行うことになっています。理由としては。。。

  1. 1. 購入いただいたお客様にできるだけ幅広い時間でのお受取りをしてもらうため
  2. 2. 受け渡しにかかるコストを削減するため
  3. 3. 受け渡し担当が長時間座ることにより発生する腰痛への対策

3つ目は冗談として…お客様の利便性と当社としての収益性を保つためにロッカーを使った受け渡しを行うことにしたのです。このロッカーの実現にあたっては下記の4案が検討されました。
大雑把に分けると、

  • ・アナログにダイヤル錠を使った運用をするか、電子キーを実装するか。
  • ・扉を共通化するか、受取人毎に別々にするか

です。これらのメリット・デメリットを大きく下記の様に分類しました。

方式メリットデメリット
1. ダイアル錠(共通扉)開発コストが小さい
運用が最も簡単
運用の負荷が大きい
セキュリティの不安が大きい
2. ダイアル錠(個別扉)開発コストが小さい
共有扉よりセキュリティが保たれ易い
運用負荷が大きい
ミスが発生しやすい
3. 電子キー(共通扉)後述の個別扉よりメンテナンスは容易開発コストが発生する
セキュリティの不安が大きい
4. 電子キー(個別扉)運用の
セキュリティ面で安全性が高い
物理面を含めると開発コストが最も大きい。
システムのメンテナンスコストも高い

私たちは上記を検討した結果、セキュリティ面での安全性と確実にお客様が商品を受け取れることを重視して案四の電子キー(個別扉)を採用することに決めました。
まぁ、開発者としては茨の道っぽいのですが… IoTは弊社としては初挑戦で、楽しそうなので良しとしましょう!構成はざっくりとこんな感じ。
ラズパイ 、SORACOM 、AWSを組み合わせた構成でラズパイ 上の言語は Node-REDを使っています。

次回からは、システム的な観点からどの様に私たちがこの電子ロッカーを構築しているのかを公開していきます!

オンライン社内勉強会のノウハウを公開!

オンライン社内勉強会はじめました!

社内のエンジニアのスキル向上を目的として勉強会を定期的に実施することになりました!完全フルリモートとなった当社で、オンライン勉強会の開催は初めてだったのですが、社員の皆さんからご好評を頂けましたので、そのノウハウを公開します!

オンライン社内勉強会のシステム構成

zoomsli.doを使って下記の構成で実施しました。1回あたりの時間は60分(厳守!)です。

スピーカーが一方的に話すばかりだと、聞いている方も辛いと思ったので双方向がやりとりできる構成にしています。sli.doを使っているのは、zoomだけだと話づらい上に、複数人同時に発言をしてしまうと話がまとまらなくなってしまうためです。

オンライン勉強会で社員間コミュニケーションを演出するために

メインスピーカーからお題を出す

こんな形でメインスピーカーからお題を出して3分間の間に色々な意見を出してもらっています。

sli.doの活用を活用する

sli.doでは色々な意見が出てくるので、メインスピーカーはそれを読み上げながら、社員同士の情報交換を促していきます。

活発な社員間のやりとり

盛り上げるためのちょっとした演出をする

また、勉強会の冒頭では下記のようなスライドを出して、できるだけ「賑やかしてもらう」ことを意識しています。

社員の皆さんからのフィードバック

勉強会終了後のアンケートでは、このような意見を頂きました!

  • シンキングタイムがリアルタイムで書き込めて面白かった
  • 盛り上げようという意識が非常に良かったです。全員でやっている感、全員が主役感を出そうとしていたと感じました。
  • たまに回答コーナーがあるので、リモートでも、参加している感が出て、集中しやすい。sli.doでみなさんのご意見が見れて参考になりました。
  • 途中途中でみんなのコメントを拾ってくれたので、人がどう考えてコーディングしているかが伝わってきた。とても興味深いし、勉強になると思う。本には載っていない、各々が経験した事例を知ることができるのがとても良い。

やはり、集中力の維持や一体感を演出する上で今回のスキームは良かったのかな、と感じています。

オンラインならではの課題

やはりネットワーク系の課題が大きかった気がします。在宅ですとスピーカーも聞くひとも使える帯域も限られるので、難しいところです。

  • 録画の影響なのかスピーカーの声がたまにロボ化してた

オンラインならでは、というわけではないのですが、

  • sil.doの最初に入れる番号をあらかじめslackとかで共有していただけると助かります!!スタート、入れてませんでした。。。

ということもあるので、sli.doを使う時には予め、イベントの番号やURLを伝えておくようにしましょう!

最後に

オンラインの開催なので盛り上がるかどうか最初はとても不安だったのですが、社員の皆さんからの温かいリアクションもあり、非常に有意義な勉強会になっていると感じています。(本当に感謝です。。。)

「松戸のwebシステム開発会社といえばジョーレン」と広く認知して頂くために、これからも社員一体となってスキルの向上に努めていきます!