Chrome拡張機能uBlacklist

ブラウザの拡張機能は使わない主義だったのですが、このTwitter投稿を見て方針転換しました。

いろんなプログラミング言語のことを調べるにあたって、最近は検索汚染が酷くて、調べたいことを検索しても中身のない/中身の薄いサイトばかりが出てくるようになっていました。なので、Python公式ページを検索するにも、site:python.org とか追加で入れないと検索に出てこない始末。広告であればせいぜい4つくらいまでしか出てこないのに、こいつら延々と出てくるんです。

なので、ブラウザの機能拡張は使わない主義を転換して、この機能拡張だけは入れることにしました。ブロックリストは正規表現で記述することにして、上記のツイートを正規表現化して以下に設定しました。(注:適宜更新します。自分のメモなので。)

/^https?:\/\/techacademy\.jp\//
/^https?:\/\/(www\.)?udemy\.com\//
/^https?:\/\/udemy\.benesse\.co\.jp\//
/^https?:\/\/dev\.classmethod\.jp\//
/^https?:\/\/www\.sejuku\.net\//

技術調べごとが楽になるといいなぁ。

ArmbianにSambaをインストール

こちらの記事でコメントを頂いた、huskyさん向けの記事になります。

この記事を作成した当時は Armbian Ubunut + OpenMediaVault は動いていたのですが、長期安定性は正直疑問があります。NASとして長期安定動作を狙う場合には、OpenMediaVaultを使うよりも素のSambaを使うほうが安定しています。
自宅にはNanoPi Neo2+NASキットが3台あるのですが、1台は素のSambaで数年間の長期運用ができています(しかも、18.04LTSから20.04LTSへのアップグレードも乗り越えました)。それより後でインストールしたOpenMediaVaultは持って1年という印象です。そして比較的最近(半年以内だったと思います)OpenMediaVaultを再インストールしたところhuskyさんの書かれている現象(インストールした後再起動すると起動してこない)に遭遇しましたので、このときは素のSambaをインストールしました。

ここでは、残っているメモから簡単(易しいという意味ではなく肝しか書いてないということです)なSambaの設定方法を紹介します。Armbian UbuntuをNanoPi Neo2+NASキットにインストールして、armbian-configからシステムをNASキット上のHDDに移動するのは完了しているものとします。(なお、システムをHDDに移動した後も、確か最初のブートローダ自体はmicroSDから読みますので、microSDは抜いてはいけません)
なお、システムをNASキットのHDDに移動しないままSambaで運用すると、先にMicroSDが死んたことがありますので、システムはHDDに移動しておいたほうがいいと思います。

“ArmbianにSambaをインストール” の続きを読む

電源周波数観測のサーバプログラム

電源周波数の変動を測ってみたという記事のコメント欄で

周波数観測サイトのWEB側のプログラムの解説記事を作っていただけないでしょうか??

という要望をいただきましたので掲載します。人に見せるために書いたコードではないのでいきあたりばったりなコードで汚いです。なお、Webプログラミングについては全くの素人です。なので、ツッコミどころ多数だと思いますが、ご容赦をw。
ソースをみるとわかるとおり、ごく簡単なロジックです。今回は折れ線グラフですが、chart.jsでは棒グラフやその他のグラフなどを簡単に出力することができますので、Raspberry Piなどを使って得たセンサーデータなどを手間をかけずにWebブラウザで見れるようにする叩き台にはなると思います。
(手間かけたくないんだったら、Ambientとかに投げちゃえばいいじゃん、という話はありますが)

“電源周波数観測のサーバプログラム” の続きを読む

プログラミング言語Elixir

世の中にはElixirというプログラミング言語があるらしい。そのうち触ってみたいとずーっと思っているのだけど、触れてない。

だから、参考になりそうな情報源だけメモしとく。

1.Exilir School

Elixir Schoolというのがあって、日本語訳がされている。
URLは https://elixirschool.com/ja/

2.Phenix v1.5 hexdocs 日本語訳

Phenixというのは、ElixirのWebフレームワークということらしい。
その公式ドキュメントの日本語訳。
URLは https://zenn.dev/koga1020/books/phoenix-guide-ja-1-5

3.Nerves

Nervesというのは組込みにElixirを使うためのフレームワークということらしい。
Elixir Schoolの中にNervesのページがある。
URLは https://elixirschool.com/ja/lessons/specifics/nerves/

公式ページはここなのだろうか?
URL https://www.nerves-project.org/platform

GitHubはここのようだ
URL https://github.com/nerves-project

Raspberry PiでLチカする記事
URL https://qiita.com/takasehideki/items/94820516ec95b85bae32

tar.gzで圧縮したファイルにzipでパスワードをかける

tar.gz で圧縮した大量のファイルに zip でパスワードをかけます。パスワードは同じものを使う前提ですので、コマンドラインで指定します。(history をクリアするなど要注意)

for i in `ls *.tar.gz`; do echo $i ; zip -e -P password ${i%.tar.gz}.zip $i ; done

これでカレントディレクトリにあるすべての *.tar.gz ファイルに同じファイル名で暗号化付きzipファイルを生成します。
内容は以下です。シェル変数の後方マッチ文字列削除をしてzipファイル名を生成しています。

for i in `ls *.tar.gz`
do
  echo $i
  zip -e -P password ${i%.tar.gz}.zip $i
done

似た作業として、すべてのディレクトリをそれぞれディレクトリ名でzip圧縮します。なおスペース(空白文字)が入ってるディレクトリ名があるとうまく行かない気がします。

for i in `ls -d *` ; do echo $i ; zip -r ${i}.zip $i ; done

KiCAD + ngspice

回路図を作成するために久しぶりにKiCADをインストールしたので、ついでにKiCADについてググってみたところ、KiCADでSPICEシミュレーションができるという記事を見かけました。
そこで、試しにやってみました。環境はLinux Mint 20です。

インストール

すでにKiCADはSynapticなどからインストールしてある状態からです。
まず、ngspice と gnucap をインストールします。(両方必要なのかはわかりません)

$ sudo apt install ngspice gnucap

次に、Linux Mint 20ではgrepとegrepがインストールされている箇所の違いから問題が出る、という記事を見かけましたので、そのワークアラウンドを探して実行しました。

$ sudo ln -s /bin/grep /usr/bin/grep
$ sudo ln -s /bin/egrep /usr/bin/egrep

回路図の作成

新規プロジェクトを作成し、回路図(.sch)をダブルクリックして開きます。

必要なシンボルを配置していきますが、シンボル選択で spice と入力するとspiceシミュレーションができるシンボルだけを絞り込み表示できます。

電圧源を選択したところ。

回路図を作成し、各部品にリファレンス(部品番号)と定数を設定します。
今回はCRローパスフィルタのシミュレーションをしてみます。

抵抗値は1kΩ、コンデンサは1uFとしました。カットオフ周波数は

となりますので、計算上は 1÷(2×3.14×1000×10^-6) = 159.24Hz となります。
電圧源は右クリックして、「プロパティを編集」を開いた後、「Spiceモデルを編集」をクリックしてパラメータを設定します。

ここでは、DC/AC解析のAC振幅に1V、過渡応答解析のパルスに以下の設定を行いました。

SPICEシミュレーションの実行

「ツール」⇒「アノテーション」、「ツール」⇒「ネットリストを生成」とした後、「ツール」⇒「シミュレータ」でシミュレータの画面を開きます。

「設定」で「AC」タブを開いて、以下の設定を行います。

「実行」ボタンをクリックした後、プローブをクリックして、回路図上のコンデンサの端子をクリックすると、周波数応答が表示されます。右上の信号欄で信号を選んで「カーソルを表示」とすると、グラフ中にカーソルを表示できます。

カーソルを移動することで、位相遅れが-45°になる周波数は159.115Hz、この周波数でのゲインは-3dBVとなり、机上計算の通りであることが確認できます。

設定で「過渡応答」タブを開いて、

として、同様に「実行」をクリックしてからプローブで抵抗の両端をクリックしすると、それぞれの位置での過渡応答波形が表示されます。

拡大したい部分を選択すると、

過渡応答波形が表示されます。

細かい使い方がまだわかりませんが、インストールで躓くことなく簡単に使えるのは嬉しいです。LTSpiceのようにWine上でエミュレーション動作させるのではなく、ネイティブ(?)に動作させられるのが良いです。

こちらの記事を参考にさせてもらいました(基本、なぞっただけです)。

CO2モニタ3号機にLCDを追加

先に作成したCO2モニタ3号機(MH-Z19C搭載)にキャラクタ液晶を追加しました。今回は凝った表示はせずに、秋月のI2C接続小型LCDモジュール(8×2行)ピッチ変換キットをつないだだけです。電源(3.3V)とGNDとSCL、SDAを配線するだけで動くのだから簡単でいいですね。電源はSeeeduino Xiaoからもらっています。

LCDの表示を行うソースコードはLCDモジュールのAQM0802Aのライブラリで良さげなのがなかったので、直接I2Cで制御しています。

/*
  CO2ガスモニタ
*/
#include <Wire.h>

const int ledPin    = LED_BUILTIN;  // ボード上のLED(PIN_LED_13)

bool errorstat = false;
void error(bool s){
  errorstat = s;
  if(s){
    digitalWrite(ledPin, LOW);  // エラー発生、LED点灯
  } else {
    digitalWrite(ledPin, HIGH); // エラーなし、LED消灯
  }
}

// LCD(AQM0802A)の制御
void LcdDat(byte d) {
 Wire.beginTransmission(0x3E);
 Wire.write(0x40);
 Wire.write(d);
 Wire.endTransmission();
 delayMicroseconds(30);
}

void LcdCmd(byte d) {
 Wire.beginTransmission(0x3E);
 Wire.write(0x00);
 Wire.write(d);
 Wire.endTransmission();
 delay(2);
}

void InitLCD(){
  // OSC,Contrast,Power/ICON/Contrast,Follower
  const byte seq1[6] = {0x38,0x39,0x14,0x70,0x56,0x6C};
  // ClearDisplay & Display ON
  const byte seq2[3] = {0x38,0x01,0x0C};
  delay(40);
  for(int i=0;i<sizeof seq1;i++) LcdCmd(seq1[i]);
  delay(200);
  for(int i=0;i<sizeof seq2;i++) LcdCmd(seq2[i]);
}

void PrintLCD(char *txt,uint8_t len){
  for(int i=0;i<len;i++){
    LcdDat(txt[i]);
  }
}

void PrintZNum(uint16_t num){
  bool s=true;      // ゼロサプレス中
  uint16_t d=1000;  // 4桁表示
  uint16_t n=num;
  uint8_t  c,p=0,b[8];
  if(n>9999) n=9999;    
  while(d>0){
    c=n/d; n=n%d;
    d=d/10;
    if(d==0) s=false;
    if(s==false || c!=0){
      b[p++]=c+0x30;
      s=false;
    } else {
      b[p++]=' ';
    }
  }
  PrintLCD((char *)b,p);
}

#define BAUDRATE 9600   // MH-Z19との通信速度(変更不可)

uint16_t CO2;
int8_t  DEG;

byte ReadCO2[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79};
byte SCalOn[9]  = {0xFF, 0x01, 0x79, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xE6};
byte SCalOff[9] = {0xFF, 0x01, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86};
byte RetVal[9];

void setup() {
  Wire.begin();
  InitLCD();
  LcdCmd(0x80 | 0x00);  // set address 0x00
  //PrintLCD("MH-Z19C ",8);
  PrintLCD("CO2 \xc9\xb3\xc4\xde",8);
  LcdCmd(0x80 | 0x45);  // set address 0x45
  PrintLCD("ppm",3);
  
  delay(1000);
  Serial.begin(115200);
  // 基板上のLED消灯(出力HIGH=消灯)
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);

  delay(2000);
  Serial1.begin(BAUDRATE, SERIAL_8N1);  // MH-Z19Cへのシリアルポート   
  Serial1.write(SCalOn,sizeof SCalOn);
  // Serial1.write(SCalOff,sizeof SCalOff);
}

void loop() {
  // CO2センサ処理
  Serial1.write(ReadCO2,sizeof ReadCO2);
  memset(RetVal,0x00,sizeof RetVal);
  Serial1.readBytes((char *)RetVal, sizeof RetVal);
  if(RetVal[0] == 0xff && RetVal[1] == 0x86){
    CO2 = RetVal[2]*256 + RetVal[3];
    DEG = RetVal[4]-40;
    error(false);
  } else {
    error(true);
  }

  LcdCmd(0x80 | 0x40);  // set address 0x40
  PrintZNum(CO2);
  // 通常表示
  if(Serial && !errorstat){
    //Serial.print(DEG);                               
    //Serial.print(",");
    Serial.println(CO2);                                
  }

  delay(3000);
}

後で3Dプリンタでケースを作るつもりです。

MH-Z19Bのキャリブレーションについて

自動校正(Auto Calibration)についてMH-Z19Cを動かしていて気づいたことが一つ。といっても、MH-Z19Cではなく、MH-Z19Bの方。(MH-Z19Cも同じ傾向なんじゃないかとは思いますが)

この3ヶ月くらい、MH-Z19Bを搭載したCO2モニタ1号機をほとんど窓を開けずにほぼ連続運用してきました(だって、寒いですもの・・・)。24時間換気のファンが動いている(といっても、そんなにガンガン換気するものではないです)ので、部屋が無人になると数時間で400ppmくらいまで表示が落ちていました。

今回、3号機を作成して初期の校正を行うために窓をずーっと開けていたところ、表示が400ppmを切り出して、380ppmを指すようになりました。大気中のCO2濃度が400ppmを少し超えるくらいなので、これは本来ありえない数字です。このまま放置しておけばこのときの値を基準に再度自動校正がかかると思いますが、この癖は頭に入れておいたほうが良さそうです。つまり、長時間の濃度が下がりきらない環境では値が低く出力されることです。それでも何もないよりもずっとましだと思いますが、値はあくまで目安で100ppm単位くらいでざっくり相対的に捉えるべきものなのだと思います。
(CCS811のeCO2のアルコールでも屁でも何でも値が跳ね上がってしまうようなものに比べればずーーーーーーっとましだと思います)

世の中でCO2濃度測定による環境の管理を売りにしていて、400ppmを下回るような数字が出ている場合には要注意かもしれません。本来はそれほど換気は良くないのに、撮影等をするために久しぶりに窓を開けて換気しているとか、そういう可能性があるかもしれません(笑)。

MH-Z19Cをとりあえず動かしてみた

以前、CO2モニタ2号機を作ったら、どうも動作が安定しないと思ったらMH-Z19Bがフェイク品だった際に、悲しみに打ちひしがれて(大げさな^^;)MH-Z19Cを購入してしまいました。今度は、製造元のWinsen社がAliExpressに直接出店していたので、そちらから購入しています。(2月19日から秋月電子でも取扱を始めています)

直接購入すると、20個は入りそうな専用の梱包箱に入って、検査成績書がついて届きました。もちろん購入したのは1個です。

おもわず感動しましたw。

3号機の作成

で、こんな感じで組んで、ようやく動かしてみました。

MH-Z19Cの端子バージョンのものは端子が2.54mmのグリッドにあっていないため、通常の2.54mmピッチのユニバーサル基板には載せられませんので、1.27mmピッチのユニバーサル基板に搭載しました。隙間が大きめですが、ここには後でI2Cのキャラクタ液晶でも搭載して(電源は外付けですが)スタンドアローンでも動作できるようにしようかと思っています。

制御用のマイコンは当初はESP32-DevKitっぽいボードで始めたのですが、途中で電源周りできちんと5Vを出すために四苦八苦しているうちにESP32-DevKitを壊してしまいました。ですので、Seeeduino Xiaoで作り直しています。

MH-Z19Cに供給する電源については、MH-Z19Cは電源が5V±0.1Vという厳しい条件を要求しますので、USBで直接給電するとこの範囲から容易に外れてしまいます。ですので、USBのBUS電圧を一旦DC-DCステップアップコンバータモジュールで8Vに昇圧してから三端子レギュレータTA48M05Fで5Vを生成しています。

MH-Z19Cからのデータの読出しはUARTで行っています。

ソフトウェアは以前作ったMH-Z19B用で動かしてみると、ライブラリでエラーが発生しました。ですので、今回は直接コマンドを送受信することにしました。

/*
  CO2ガスモニタ
*/
const int ledPin    = LED_BUILTIN;  // ボード上のLED(PIN_LED_13)

#define BAUDRATE 9600   // MH-Z19との通信速度(変更不可)

uint16_t CO2;
int8_t  DEG;

byte ReadCO2[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79};
byte SCalOn[9]  = {0xFF, 0x01, 0x79, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xE6};
byte SCalOff[9] = {0xFF, 0x01, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86};
byte RetVal[9];

bool errorstat = false;

void error(bool s){
  errorstat = s;
  if(s){
    digitalWrite(ledPin, LOW);  // エラー発生、LED点灯
  } else {
    digitalWrite(ledPin, HIGH); // エラーなし、LED消灯
  }
}

void setup() {
  delay(1000);
  Serial.begin(115200);
  // 基板上のLED消灯(出力HIGH=消灯)
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);

  delay(2000);
  Serial1.begin(BAUDRATE, SERIAL_8N1);  // MH-Z19Cへのシリアルポート   
  Serial1.write(SCalOn,sizeof SCalOn);
  // Serial1.write(SCalOff,sizeof SCalOff);
}

void loop() {
  // CO2センサ処理
  Serial1.write(ReadCO2,sizeof ReadCO2);
  memset(RetVal,0x00,sizeof RetVal);
  Serial1.readBytes((char *)RetVal, sizeof RetVal);
  if(RetVal[0] == 0xff && RetVal[1] == 0x86){
    CO2 = RetVal[2]*256 + RetVal[3];
    DEG = RetVal[4]-40;
    error(false);
  } else {
    error(true);
  }

  if(Serial && !errorstat){
    //Serial.print(DEG);                               
    //Serial.print(",");
    Serial.println(CO2);                                
  }
  delay(3000);
}

これで、MH-Z19Cからデータを読み出してCO2濃度を出力します。Arduino IDEのシリアルプロッタ機能を使えば、時系列での変化もグラフで見ることができます。

動作させるとかなり大きめの値が出ます。MH-Z19Bのときも同じでしたが、キャリブレーションが必要なようです。風通しのいいところで24時間動かせば多分収束すると思うのですが、今回は1時間ほど窓を開けておいて(寒い!)、センサのHd端子をGNDに落として初期のキャリブレーションを行いました。たぶん、400ppmよりはかなり悪い条件だとは思いますが、オートキャリブレーションをONにしているので、そのうち落ち着くだろう、という発想です。

実際にシリアルプロッタ機能で表示させてみたものです。途中、大きく跳ね上がっているのは、MH-Z19Cに息を吹きかけた際のものです。呼気の中のCO2に反応して大きく跳ね上がっているのがわかります。