ツタンラーメンの忘備録

プログラミングや精神疾患、ラーメンについて書いていきます。たぶん。

Arduino analog入力 足りない 増やす

意外とまとまっているサイトがなかったのでまとめておく。
Arduinoのアナログ信号はA0~A5の6つしかない。

が、増やす方法がないわけではない。

方法は二つ(初心者なので厳密にはいろいろ違うことを許してほしい)
・ADコンバータを使う
・MUX(マルチプレクサ)を使う

これら。デジタル信号を増やしたいときはIOエキスパンダーとか言うのがある。これも面白いのであとで記載したい。

とりあえず方法を教えろ、原理はあとで勉強するという人向けの記事であることを最初に述べておく。


まずADコンバータ
f:id:hungrykirby:20170826191005j:plain
こんな回路になる。詳しい説明はいつか解説したい。
画像では薄くてわかりづらいが、小さな丸と凹みの部分をちゃんと確認してください(名前の方向は関係ない)

用いたのは

である。
コードは下に記載されている二つの記事のうち上のやつものがそのまま動く

電子部品使い方:マイコンのADC(MCP3208)変換
sites.google.com
参考にした記事

上記記事を見るといろいろ注意書きがあるので、ちゃんと使う人はちゃんと勉強した方がいいと思う。


次にMUX

f:id:hungrykirby:20170911160658j:plain
こんな回路になる

用いたのは

である。
コードは下記ライブラリが古いが使える。

github.com

適当に描いたコードを

#include <Mux.h>

Mux mux;
int counter=0;
void setup(){
  Serial.begin(9600);
  mux.setup(5,4,3,2,A0);
}

void loop(){
  
  int val = mux.read(counter);
  
  if(counter==15){
    Serial.println(val);
    delay(1000);
  }else{
    Serial.print(counter);
    Serial.print(":");
    Serial.print(val);
    Serial.print(", "); 
  }
  
  counter = ++counter & 15;
  
  delay(50);
}

このうち0しか使っていないので、他の値は乱れがち

Flask SQLAlchemy alembicでtable、columnを作成したい。ついでにherokuにデプロイしたい

# sqlalchemy.url = driver://user:pass@localhost/dbname
sqlalchemy.url = sqlite:///test.db

alebmic.initを正しいパスに変更する。
当たり前であるがこれを忘れて死んでいた。

Tutorial — Alembic 0.9.6 documentation

じゃあ、これをデプロイしようとして意外とはまった
floder構成は


+alembic
 env.py
 +versions
  +???.py
app.py
config.py
alembic.ini

みたいな感じ

env.py

import app #app.pyから呼んでくる

#
#~そのまま~
#

def run_migrations_online():
    #下記を加える
    alembic_config = config.get_section(config.config_ini_section)
    alembic_config['sqlalchemy.url'] = app.app.config['SQLALCHEMY_DATABASE_URI']
    connectable = engine_from_config(
        alembic_config,
        prefix='sqlalchemy.',
        poolclass=pool.NullPool)
    #上記を加える
    
    '''
    #既存のコード
    connectable = engine_from_config(
        config.get_section(config.config_ini_section),
        prefix='sqlalchemy.',
        poolclass=pool.NullPool)
    '''

    with connectable.connect() as connection:
        context.configure(
            connection=connection,
            target_metadata=target_metadata
        )

        with context.begin_transaction():
            context.run_migrations()

stackoverflow.com
フォルダ構成が違うだけでこれが参考になる

python 暗号化 複合化 テキスト 保存

Pythonで暗号化と復号化 - Qiita

これの延長。暗号化した文字列をテキストファイルに保存したいという謎の欲求により生まれたコード

import base64
from Crypto import Random
from Crypto.Cipher import AES

import string, random

class AESCipher(object):
    def __init__(self, key, block_size=32):
        self.bs = block_size
        if len(key) >= len(str(block_size)):
            self.key = key[:block_size]
        else:
            self.key = self._pad(key)

    def encrypt(self, raw):
        raw = self._pad(raw)
        iv = Random.new().read(AES.block_size)
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return base64.b64encode(iv + cipher.encrypt(raw))

    def decrypt(self, enc):
        enc = base64.b64decode(enc)
        iv = enc[:AES.block_size]
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return self._unpad(cipher.decrypt(enc[AES.block_size:]))

    def _pad(self, s):
        return s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs)

    def _unpad(self, s):
        return s[:-ord(s[len(s)-1:])]

def writeEncrypted(inputtext, filename, key):
    cipher = AESCipher(key)
    encryptedtxt = cipher.encrypt(inputtext)
    f = open(filename, 'w')
    f.write(str(encryptedtxt).split("\'")[1])
    f.close()

def openDecypt(filename, key):
    cipher = AESCipher(key)
    f = open(filename)
    data = f.read()
    f.close()
    print(cipher.decrypt(data.encode('utf-8')))


if __name__ == '__main__':
    key = ''.join([random.choice(string.ascii_letters + string.digits) for i in range(50)])
    print(key)
    writeEncrypted("hogehuga", "hogehuga.txt", key)
    openDecypt("hogehuga.txt", key)

特殊なことはしていないんだけど
byte->strするときに

b'aiueo'

みたくなるので暗号化した部分だけ取りだす

Chart.jsで以前描画したものが残る問題を解決する

mussyu1204.myhome.cx

var chart; //グローバル変数にする

const display_graph = function(scores, labels, colors, date){
  const doughnutData = {
    labels : labels,
    datasets : [{
      fill:false,
      tension:0,
      label: date,
      backgroundColor: colors,
      data : scores
    }]
  }
  const ctx = document.getElementById("chart-area").getContext("2d");
  ctx.canvas.width = 600;
  ctx.canvas.height = 400;
  if(chart){
    chart.destroy(); //すでにグラフが存在すれば消す
  }
  chart = new Chart(ctx, {
    type:'doughnut',
    data:doughnutData,
    options: {
      legend: {
        labels: {
          fontSize: 24
        }
      }
    }
  });
};

この二つをやればいい。

Flask fullchallender.js ajax クリックした日付に対応した情報をFlask側に送る

これも全然難しい話ではなかったのだが、凡ミスでつまずいた。

//callender.js
const my_cal = function(){
  $(document).ready(function() {

    $('#calender').fullCalendar({
      dayClick: function(date, jsEvent, view) {
        const send_date = JSON.stringify(date.format('YYYY-MM-DD'));
        $.ajax({
          type:'POST',
          url:'/fetchday',
          dataType:'json',
          data:send_date,
          contentType:'application/json',
          success:function(success_data){
            console.log(success_data);
          },
          error: function(error) {
            console.log("error");
            console.log(error);
          }
        });
        return false;
      }
    });
  });
}
#app.py
@app.route('/fetchday', methods=['POST'])
def fetch_day_data():
    get_json = request.json
    print(get_json)

    return_json = {
        "hello":"world"
    }

    return Response(json.dumps(return_json))

これで動くかな。ところどころ端折ってい待っているので動かないかも。

Flaskでlist状のdictをhtml上に展開する。

やってみれば簡単なんだけど

やりたいこと:
長さの同じ配列が二つある。一つの値をoptionのvalueに、もう一つを表示される値に使いたい。

@app.route('/action', methods=['POST'])
def arrange_form_nums():
    title = "yeah!"
    option_value = [0, 1]
    option_text = ["option1", "hya"]
    options = [{"value":v, "text":t} for (v, t) in zip(option_value, option_text)]
    print(options)
    return render_template('forms.html',
        title=title,
        options=options)
<select name="test-select">
  {% for o in options %}
    <option value="{{o.value}}">{{o.text}}</option>
  {% endfor %}
</select>

form作成できるやつ使った方が楽な気がしてきた。

python osc openframeworks keyboardinput pythonでoscを受信しながらキーボード入力を受け付ける。

openframeworksからキーボード入力を送れば解決なのでは?という声が聞こえてきそう…。

python

import argparse
import math

import re
import threading
import sys

from pythonosc import dispatcher
from pythonosc import osc_server

import config

import osc

def keys():
    while True:
        input_word = input(">")
        if input_word == "s":
            sys.exit()

def osc_loop():
    parser = argparse.ArgumentParser()
    parser.add_argument("--ip",
      default="localhost", help="The ip to listen on")
    parser.add_argument("--port",
      type=int, default=1111, help="The port to listen on")
    args = parser.parse_args()

    _dispatcher = dispatcher.Dispatcher()
    _dispatcher.map("/found", osc.set_found)
    _dispatcher.map("/raw", osc.print_raws)

    server = osc_server.ThreadingOSCUDPServer(
      (args.ip, args.port), _dispatcher)
    print("Serving on {}".format(server.server_address))
    server.serve_forever()



dual_loop = threading.Thread(target=osc_loop,name="dual_loop",args=())
dual_loop.setDaemon(True)
dual_loop.start()

if __name__ == "__main__":
    keys()

threadingのtargetを逆にすると正しく動作しない。これで本当に正しく動いているのだろうか。

dispatcher = dispatcher.Dispatcher()

とするとうまく動かないので注意。_から始めるべきでないのはわかっている。