プログラミング素人のArduino

技術屋の末端。プログラミングは専門外。 電気回路も専門外です。 コードに間違いなど見つけられたら、気軽にコメントください。 VC#始めました。

「実装しない」機能の決め方 – 週休7日で働きたい

「実装しない」機能の決め方 – 週休7日で働きたい

 

なるほど、耳が痛い。

だが一方で、それが出来るのも趣味だからこそ。

アルゴリズムをはじめよう

アルゴリズムとは「問題を解決するための手順をもれなく表現したもの」。
プログラミングをするにあたっては、まず初めに考えるものです。

例えば、文字列を表示したいなら

Console.WriteLine("*****");

であったり、

MessageBox.Show("*****");

といったものを使う、ということを考えて組み立てていきます。
このように、すでに関数として完成しているものではそのまま使うことができますが、

・土壌湿度が下がったら
・ポンプをオンにして
・一定時間経過したら
・ポンプをオフにする
※自動水やり器のアルゴリズム

このようなものもアルゴリズムの一つです。

プログラムはそのほとんどが、じつは「for」と「if」の組み合わせで表現することができます。
・関数として出来上がっているものをどのような順番で呼び出すか?
・関数がなければその処理をどのように「for」と「if」の組み合わせで実現するか?
が、アルゴリズムの設計です。

そこで、私は最初の一歩としてこの本を選択しました。

アルゴリズムを、はじめよう

アルゴリズムを、はじめよう

基本的な、主にデータの並べ替え(ソート)や抽出について丁寧に説明されています。
また、流れ図(フローチャート)と疑似言語ですべての例が説明されています。

フローチャートは考えをまとめるときや説明するときにも使えますので、プログラマでなくても使えると便利です。

疑似言語は慣れないとむしろ若干わかりにくいですね。
"if(i<5)" なら "i<5"と書かれていたり、
"i=5" を "5→i" と書いていたりします。
C言語と疑似言語の関係

内容的には少なめだと思いますが、ここに出てくるようなものがプログラミングできるようになれば一段階複雑な問題にも取り組めるようになると思います。

この次ぐらいにこちらをみると、さらに多くの例にふれられると思います。

アルゴリズム図鑑 絵で見てわかる26のアルゴリズム

アルゴリズム図鑑 絵で見てわかる26のアルゴリズム

Androidiphoneアプリで一部が無料で見られます。
こちらは、アルゴリズムをアニメーションで説明していて動きはわかりやすいですが、いきなりこちらを見てもプログラミングは難しいかもしれません。

勉強の目標を立てるために一度見てみると、意欲がわくのではないでしょうか?

プログラムファイルにアイコンを設定する

デフォルトではexeアイコンはこんな感じですが。
f:id:s51517765:20170624190422j:plain

特徴のあるアイコンにしてみました。
f:id:s51517765:20170624190428j:plain

プログラム実行時も左上に表示されます。
f:id:s51517765:20170624190434j:plain

素材はこちらからいただきました。
加工もOKということです。
hiyokoyarou.com

こちらで .icoファイルに変換します。
JPEG/PNG/GIFからアイコンを作成する「アイコン コンバータ」

ソリューションエクスプローラでソリューション名(ここではtwitter)を右クリックし、プロパティを開きます。
f:id:s51517765:20170624190841j:plain
リソース¥アイコンとマニフェストを選択し、「アイコン」にファイルを選択します。

次にForm1.cs[デザイン]を選択し、Iconを選択し、.icoを設定します。

「リリース」を行えば完成。

Twitterへの自動投稿

Twitter APIを利用して、定期的にTweetするものを作りました。
f:id:s51517765:20170622223753j:plain

以前の記事の発展。
s51517765.hatenadiary.jp

CoreTweetの基本機能はこの辺を参考に。
blog.ch3cooh.jp

テキストファイルからStreamreaderで読み込んで、ランダムにTweetします。

private void timer1_Tick でタイマー設定。
(プログラミング初心者にありがちな失敗は Thread.Sleepメソッドを使ってしまうこと。Windowsのグルグルが出てきて何もできなくなってしまいます。)
private void AutoTweet() がTweetの本体。
private void buttonPause_Click が自動投稿の停止。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using CoreTweet;
using System.Diagnostics;
using System.IO;
using CoreTweet.Streaming;

namespace twitter
{
    public partial class Form1 : Form
    { 
       public Boolean AutoTweet_bool = false;
       public int Set;    //Next Tweet time
       public int interval;     //Tweet Interval

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {             
     
            var tokens = Tokens.Create("******", "******", A_Token, A_TokenSecret);        

 	//Auto Tweet Interval
            comboBoxInterval.Items.Add("15");
            comboBoxInterval.Items.Add("30");
            comboBoxInterval.Items.Add("59");
            comboBoxInterval.Text = "59";
        }

        private void button_AutoTweet_Click(object sender, EventArgs e)
        {
            interval = int.Parse(comboBoxInterval.Text);
            button_AutoTweet.Enabled = false;
            buttonPause.Enabled = true;
            AutoTweet_bool = true;
    
            if (interval > 59)
            {
                interval = 59;
                comboBoxInterval.Text = "59";
            }

            DateTime Now = DateTime.Now;
            timer1.Start();                 // タイマー起動
            Set = Now.Minute + interval;

            if (Set > 59)
            {
                Set = Set - 60;
            }

            AutoTweet(); //初回Tweet
        }

        private void timer1_Tick(object sender, EventArgs e)   //タイマー
        {
            if (AutoTweet_bool == true)
            {
                DateTime Now = DateTime.Now;
                if (Now.Minute == Set)
                {
                    Set = Now.Minute + interval;
           if (Set > 59)
                 {
                    Set = Set - 60;
                 }
                   
                        AutoTweet();
                }
            }
        }

       private void AutoTweet()
        {
            int ListCount=0;
    
                string AutoTweetText = "";
                System.IO.StreamReader sr = new System.IO.StreamReader(@"C:\Users\***\List.txt", System.Text.Encoding.UTF8);                //ファイルを絶対参照で指定したいときは先頭に@を使う
                int LineCount = 1;
            button_AutoTweet.Enabled = false;
            while (sr.Peek() >= 0)
            {
                //一行ずつ読み込む
                AutoTweetText = sr.ReadLine();
                ListCount++;
       
            }
            sr.Close();

            System.Random r = new System.Random();
            int rand = r.Next(1,ListCount);  //LineCount
  
               System.IO.StreamReader sr2 = new System.IO.StreamReader(@"C:\Users\***\List.txt", System.Text.Encoding.UTF8);

            while (sr2.Peek() >= 0)
                {
                    //一行ずつ読み込む
                    AutoTweetText = sr2.ReadLine();
                    LineCount++;
                    if (LineCount == rand)
                    {
                        break;
                    }
                }
                //閉じる
                sr2.Close();
       
           try
             {
                    var tokens = Tokens.Create("******", "******", A_Token, A_TokenSecret);
                if (checkBoxDebug.Checked == false)
                {
                    tokens.Statuses.Update(status => AutoTweetText); //tweet
                }
                else
                {
                    MessageBox.Show(AutoTweetText);
                }
                    DateTime dt = DateTime.Now;
                    textBoxStatus.AppendText(dt.ToString("HH:mm:ss") +" "+AutoTweetText.Substring(0,17) +"… Complete!" + Environment.NewLine);
             }

           catch
            {
                    DateTime dt = DateTime.Now;
                    textBoxStatus.AppendText(dt.ToString("HH:mm:ss") + "Auto Tweet Error!" + Environment.NewLine);
            }
        }

        private void buttonPause_Click(object sender, EventArgs e)
        {
            buttonPause.Enabled = false;
            button_AutoTweet.Enabled = true;
            AutoTweet_bool = false;
        }
    }
}

Arduino nano互換 格安中華Bord(HiLetgo)

Amazonで格安Arduino互換品を購入。

送料込みで330円。
中国からの発送のため2週間ぐらいは掛かりますが。

f:id:s51517765:20170603130915j:plain

ピンヘッダは自分ではんだ付けする必要があります。
オスピンが付属していますが、他のオス-オスのジャンパワイヤが使いたいこともあり、本家Arduinoのようにメスのヘッダピンをつけました。

これで、Arduino IDEで接続を試みるも書き込みができません。
Amazonoのレビューを参考に下を参照し、CH340のドライバをインストールします。
Arduino NANO 互換品(CH340チップ使用)のデバイスドライバー | ネクストステップ サポートBlog

これで、書き込みができるようになりました。

ようするに、本家とはチップが異なるためそのドライバを追加しなければならないということです。


HiLetgo Mini USB Nano V3.0 ATmega328P CH340G 5V 16M マイクロコントローラーボード Arduinoと互換

Arduino(nano)と同じようにAnalog I/Oの機能があるはずなのだが、何か設定が必要なのだろうか?
analog出力がdigital出力のようになっている。
PWMを設定すると150ぐらいでHIGHとLOWが切り替わる。
AnalogReadは機能しているようだ。

C#でウェブスクレイピング

今回はウェブスクレイピングをやってみます。
↓の続きになります。
s51517765.hatenadiary.jp

ウェブスクレイピングとして、Webの情報を取得する基本的な構文は↓を参考にしました。
www.casleyconsulting.co.jp

Visual Studio上でクラスファイルを追加して、ウェブスクレイピングのコードを作成します。
f:id:s51517765:20170505154304j:plain

これは、URLを指定するとそのページのHTMLをstring型の文字列として取得します。
この内容は、あまり深く考えずにこういう一つのメソッドとして理解しておけばとりあえずいいと思います。

        public string Gethtml(string url)
        {
            // 指定されたURLに対してのRequestを作成します。
            var req = (HttpWebRequest)WebRequest.Create(url);     //using System.Net;

            // html取得文字列
            string html;

            // 指定したURLに対してReqestを投げてResponseを取得します。
            using (var res = (HttpWebResponse)req.GetResponse())
            using (var resSt = res.GetResponseStream())
            // 取得した文字列をUTF8でエンコードします。
            using (var sr = new StreamReader(resSt, Encoding.UTF8))     //using System.IO;
            {
                // HTMLを取得する。
                html = sr.ReadToEnd();
            }

            return html;
        }

このとき、System.NetとSystem.IOを使いますので、以下をファイルの先頭に追加しておきます。

using System.Net;
using System.IO;

つぎに、同じクラスファイル上にキーワードを抽出するプログラムを作成します。
引数としては先ほどのメソッドで取得したHTMLとキーワードを指定します。
考え方としては、Keywordを含む文を<P></P>で囲まれる部分で区切り取得します。
f:id:s51517765:20170506121935j:plain

①まずHTML全体の中からKeywordをさがす。html.IndexOf(Keyword)構文でhtmlのなかでKeywordの位置を探します。
Substring(start,Length)構文で、start =0(最初)から前記Keyword位置までを取得。
②前記Keywordよりまえの部分の中から後ろからさがして<p>を探す。
ここでは、Keywordから前へひとつづつ文字を追加して<p>をさがし、見つかったらこれがほしいKeywordより前の部分になります。

for (int n = 1; n <= buf_buf_mae.Length; n++)
            {
                buf_mae = buf_buf_mae.Substring((buf_buf_mae.Length) - n, n);

③~⑤後ろは同様に</p>を探します。
これを足し合わせるとKeywordを含む文が取得できます。

string getWord = buf_mae + buf_ushiro;

これをまとめると、Keywordの取得メソッド

        public string GetKeyword(string html, string Keyword)
        {
        header = "<p"
        footer = "</p"

            // html文字列内からKeywordをさがしその位置を返す
            int keywordStart = html.IndexOf(Keyword);

            string buf_buf_mae = html.Substring(0, keywordStart);
            string buf_mae = "";
            for (int n = 1; n <= buf_buf_mae.Length; n++)
            {
                buf_mae = buf_buf_mae.Substring((buf_buf_mae.Length) - n, n);
                if (buf_mae.IndexOf(header) > 0)
                {  //後ろからさがして見つかったら
                    break;
                }
                if (n > 5000)
                {
                    MessageBox.Show("Header get Error.");
                    break;
                }
            }

            string buf_ushiro = html.Substring(keywordStart); //indexOfから後ろを取得第2引数省略
            int nagasa_u = buf_ushiro.IndexOf(footer);
            buf_ushiro = html.Substring(keywordStart, nagasa_u + 4); //start位置,対象文字列長さ

            string getWord = buf_mae + buf_ushiro;
            return getWord;

        }

次にForm1にHTMLのボタンクリックイベントを作成します。

     private void buttonGethtml_Click(object sender, EventArgs e)
        {
            ViewBoxBackColorSet();

            if (checkBoxWriteOut.Checked == false && checkBoxPreview.Checked == false)
            {
                MessageBox.Show("Select output");
            }
            else
            {
                DateTime dt = DateTime.Now;
                string date = dt.ToString("yyyy_MM_dd_HH_mm_ss");
                try
                {
                    textBoxPreview.AppendText(dt.ToString("HH:mm:ss" + Environment.NewLine));

                    var scr = new Scraping();  //クラスScrapingを使うためにインスタンス作成
                    string url = textBoxURL.Text;
                    string html = scr.Gethtml(url);

                      Keyword = comboBoxKeyword.Text;
                    
                    string getWord;
                    getWord = scr.GetKeyword(html, Keyword);
                    if (checkBoxPreview.Checked == true)
                    {
                        textBoxPreview.AppendText(getWord + Environment.NewLine);
                    }
                    if (checkBoxWriteOut.Checked == true)
                    {
                        using (StreamWriter writer = new StreamWriter("H_" + date + ".txt", true))
                        {
                            writer.Write(getWord);
                        }
                    }

                }
                catch
                {
                    MessageBox.Show("Check URL");
                }
                ViewBoxBackColorReset();
            }
        }

このへんがオブジェクト指向(クラス設計)っぽいところ。
クラスを使うためにインスタンスの宣言をして、入力(ここではURL)と出力(ここではHTML)(および、HTMLとKeywordとWord)だけが見えている状態になります。

 var scr = new Scraping();  //クラスScrapingを使うためにインスタンス作成
 string url = textBoxURL.Text;
 string html = scr.Gethtml(url);

 string getWord;
 getWord = scr.GetKeyword(html, Keyword);

これで、必要部分は取得できましたが、HTMLのタグが不要です。
f:id:s51517765:20170506123724j:plain

  public string deleteTag(string getWord)
        {
            int buf_int = -1;
            int buf_int2;
            string tukau1, tukau2;
            string buf_1;
            string deleteTag_getword;

            for (int n = 1; n < 80; n++)
            {
                buf_int = getWord.IndexOf("<");
                if (buf_int < 0)
                {
                    break;
                }

                tukau1 = getWord.Substring(0, buf_int);
                buf_1 = getWord.Substring(buf_int + 1);
                buf_int2 = buf_1.IndexOf(">");
                tukau2 = buf_1.Substring(buf_int2 + 1);

                getWord = tukau1 + tukau2;
              
            }
            deleteTag_getword = getWord;
                 return deleteTag_getword;
        }

このように<>で囲まれた部分をHTML Tagとみなして削除するメソッドを入れると、すっきりします。
タグのスタート<を探し、これ以前の文字列を取得し、<の次の文字から>を探しこれをタグとみなして捨てる。>の次の文字から同じようにタグを探し、文字列を取得し最初に取得したタグの外とつなげて…という風にしていきます。
forの構文の繰り返し数は適当にいれていますが、タグが見つからなくなったら、IndexOf = -1となるので、こうなったらBreak;で終了。

bufはbufferの略であまり綺麗とは言えないがよく使われる一時的な変数のことです。

f:id:s51517765:20170506125852j:plain

※HTMLのタグは「半角<>」を使いますが、ブログ上で半角<>を使うタグとみなされて表示されないので、全角<>を使っています。

C#でTwitterにつぶやく

このページを参考にC#からTwitterにつぶやいてみたいと思います。
blog.clock-up.jp

パッケージマネージャーコンソールから、ライブラリを導入します。
パッケージマネージャーコンソールは下の図のように開きます。
f:id:s51517765:20170507134201j:plain
すると、↓のようなコンソールが開くので、
f:id:s51517765:20170507134301j:plain

Install-Package CoreTweet

と入力します。

次にAPIキーを入手します。
twiiterアカウントに電話番号の登録が必要になります。
apps.twitter.com

ライブラリの登録をして、

using CoreTweet;
using System.Diagnostics;

ボタンクリックイベントを作ります。
最終的にはPincode入力用のFormを作りますが、今は簡易的にMessageBoxを出して、
その間に、Twiiterの認証画面を通過して、直接プログラムを書き換えてPincodeを通しています。
なんか、あらかじめブラウザでTwiiterにLogInしていないと、通らない???

 private void button1_Click(object sender, EventArgs e)
        {
            var session = OAuth.Authorize("*********", "*********");
                          //("入手した api_key", "入手した api_secret");
            Process.Start(session.AuthorizeUri.AbsoluteUri);

            MessageBoxShow("Get Pincode.");  //ここでPincodeの入力待ち

            var pincode"123234545676";   //ここを書き換える

            //トークン取得
            var tokens = OAuth.GetTokens(session, pincode);

            try
            {
                tokens.Statuses.Update(status => "hogehoge");
            }
            catch 
            {
                MessageBox.Show("Error");
            }

        }

で、APIは通ったようでプログラムはErrorがないのにタイムラインにつぶやきが更新されないのはなぜ???

<5/9更新>
APIAccess LevelがReadになっていて、Write権限がなかったため、書き込みができなかったらしい。
Read and writeに設定したはずだが、画面上ではRead and writeと出ていても、Read Onlyになっていることがあるようだ。
一度 Read, Write and Access direct messagesに変更して保存し、Read and writeに戻したら有効になった。
f:id:s51517765:20170509213451j:plain
<5/25更新>
APIが通っても一度しかTweetが成功しないことが続いた。数時間経過後に再びTweetができるのだが、どうやら同じ内容を連続してTweetしようとすると、Twitter側から弾かれるらしい。