2022年12月26日月曜日

lan-sw16p/maのコンデンサ交換

 ハブが調子悪かったので、新品にかえてもらったが、不具合のあるほうを、試しにコンデンサチェックしてみた。すると、470uF 16V 一個が、はんだごてで とりはずそうとすると、なぜか、ピンがするっとぬけてしまう。コンデンサからピンが抜けるのは、加熱したからと言って、あまり経験したことがない。もう1個、470uFがあったので、合計2個、手持ちの電解コンデンサと交換してみた。とりあえず、動作はOk,あとは、不安定にならないかどうか、試しに使ってみてもいいかもしれない。これで直ったら、もうけものだが。

 ちなみに、ぬけたピンをさして、容量を測定してみても、容量抜け?だろうか、0だった。接触不良の可能性もあるが。

2022年12月22日木曜日

Gasで血圧記録

 gasで即席でつくってみた。値を選択式にすると、もう少し使いやすかも。

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
      <script src="https://code.jquery.com/jquery-3.6.1.slim.min.js"  integrity="sha256-w8CvhFs7iHNVUtnSP0YKEg00p9Ih13rlL9zGqvLdePA="  crossorigin="anonymous">
      </script>
  </head>
  <body>
    <div  style="font-size:large;">
    <input type="text" id="hiduke" value="" style="font-size:large;">
    <input type="text" id="jikoku" value="" style="font-size:large;">
    <br>High
    <input type="text" id="high" value="" style="font-size:large;"><br>
    Low
    <input type="text" id="low" value="" style="font-size:large;"><br>
    脈
    <input type="text" id="myaku" value="" style="font-size:large;">
    <button id='Enter' onclick="Enter()">保存</button>
    <div id="msg"></div>
    </div>
    <div><a href="https://docs.google.com/spreadsheets/d/シートID/edit#gid=0">シート</a></div>
  </body>
</html>
<script>
   window.onload =   function(){   
    let today=new Date();
$('#hiduke').val(formatDate_dateOnly(today));
$('#jikoku').val(formatDate_jikoku(today));
   }


function formatDate_jikoku(dt) {
  var y = dt.getFullYear();
  var h=('00' + dt.getHours()).slice(-2);
  var mi=('00' + dt.getMinutes()).slice(-2);
  return (h+':'+mi);
}

function formatDate_dateOnly(dt) {
  var y = dt.getFullYear();
  var m = ('00' + (dt.getMonth()+1)).slice(-2);
  var d = ('00' + dt.getDate()).slice(-2);  
  return (y + '/' + m + '/' + d);
}

function Enter() {
        let hiduke =$('#hiduke').val();
         let jikoku =$('#jikoku').val();
          let high =$('#high').val();
           let low =$('#low').val();
            let myaku =$('#myaku').val();
            google.script.run.withSuccessHandler(onSuccess).withFailureHandler(onFailure).Set(hiduke,jikoku,high,low,myaku); 
  }
  function onSuccess(res){
    $('#msg').text(res);
  }
  function onFailure(res){
     $('#msg').text(res);
  }

  </script>

*****************
function doGet(e) {
  return HtmlService.createTemplateFromFile("index").evaluate();
}


function Set(hiduke,jikoku,high,low,myaku) {

  let spreadSheet = SpreadsheetApp.openById(シ-トID);
   let sheet = spreadSheet.getSheetByName('シート1');

   let lastrow = sheet.getLastRow();

   sheet.getRange(lastrow+11).setValue(hiduke);
   sheet.getRange(lastrow+12).setValue(jikoku);
   sheet.getRange(lastrow+13).setValue(high);
   sheet.getRange(lastrow+14).setValue(low);
   sheet.getRange(lastrow+15).setValue(myaku);


   return "送信済み"
  }

2022年12月11日日曜日

GASによるグループウエア

 グループウエアをGASで作ってみた。

データベースが使えないので、いろいろ制限があり大変だった。無料だから仕方ないとは思う。

回覧メッセージの未読チェック機能をスプレッドシートで、宛先の選択の工夫をJqueryで、という具合に。

表示遅い分少しでも、和らぐようにSPAにしてみた。

エクセルは、PCのGdriveリンクを共有で使うようにして、エクセルからスプレッドシートへの変換は、トリガーで毎分変更をチェックしながら行っている。

その他、文字修飾可能にすること、メッセージを2週間分に制限するため、自動削除機能をつけたこと。削除までの日数は、投稿者が選択できるようにしたこと。メッセージは、必要に応じて、GmailにPDFで送って、自分で保管もできるようにしたこと。

 等々、いろいろ対処したおかげで、完成まで数か月かかった。あと少し調整が必要かも。残念ながら、OSのせいか、自分のPCでは、C#のツールチップによる未読お知らせ機能を入れようとしたが、なぜか反応しない。仕方ないので、画面はFormにして、透明度を時間とともに変えるような実装にした。また、GASで作ったサイトをWebAPIとして、C#から読み取ろうとしたが、非常に面倒なのであきらめた。Gdriveにユーザーごとのファイルを作成して、それを経由して未読情報を、Gdriveの共有から読み取るようにしてみたらなんとかうまくいった。力技という感じだが、そもそもGASという言語を使っているので、このぐらいは仕方ないのでないかと思う。

2022年11月3日木曜日

jquery 動的にイベント追加

 appnedした場合、動的なイベントの追加には、工夫がいるようだ。

$("親要素").on('click', '該当する要素', function(e){

  var tmp=e.target.id;

});

のように利用できる。

ちなみに、以下の方法はだめだった。

$("該当する要素").change(function(e) {

  var tmp=e.target.id;

 });

     

2022年10月22日土曜日

GAS使ってグループの名前リストを作成

 権限の関係でグループのEmaiアドレスは取得できても、名前が取得できないことがあるようだ。画面上では表示されているが、ダウンロードはEmaiのみ。ただし、Chromeで、「名前を付けて保存」>ファイルの種類を「ウエブページ、完全」 を選択して保存すると、UTF8で全角文字できちんと保存されるので、面倒だが、このデータをGdriveに持って行って、GASでパースすることにした。

GASは、データを保存したいスプレッドシートに、スクリプトを作成する。この場合、Parseというライブラリの追加が必要。2022.7現在、ライブラリのIDは

1Mc8BthYthXx6CoIz90-JiSzSafVnT6U3t0z_W3hLTAX5ek4w0G_EIrNw

もっと簡単な方法がありそうだが、とりあえず、以下のスクリプトで、無事 Emailと名前のリストが取得できた。


function member_parse() {

var contents = DriveApp.getFolderById('ここにフォルダのID')
.getFilesByName('メンバーリスト.html')
.next()
.getBlob()
.getDataAsString("utf8");
//Logger.log(contents); let mList= new Array();
let eList= new Array(); names = Parser.data(contents).from('<div class="LnLepd">').to('</div>').iterate();
emails=Parser.data(contents).from('Sq3iG" href="mailto:').to('</a>').iterate(); for(nm of names){
mList.push(nm);
} var ci=0;
for(em of emails){
if (ci % 2 ==0){ eList.push(em.split('>')[1]);}
ci++;
}
//console.log(zip(eList,mList));
NameEmailList=zip(eList,mList); var sheet = SpreadsheetApp.openById('ここにスプレッドシートのID').getSheetByName('shokuin'); for (gyo of NameEmailList){
sheet.appendRow(gyo);
} } const zip = (...arrays) => {
const length = Math.min(...(arrays.map(arr => arr.length)))
return new Array(length).fill().map((_, i) => arrays.map(arr => arr[i]))

}


GASとスプレッドシートを組み合わせて、コードを書いていると、ちょうどエクセルのマクロを使っているような感覚になる。ちょっとした操作で、シートの動作が変わって、コードがうまく動かなくなることも。無料なので、手間はかかるのは仕方ない。半面、シートで実際のデータがどうなっているか、すぐ確認できるよさはある。

2022年10月15日土曜日

android Ver10 への自作アプリインストール

 以前つくった、sumahoCopyなる自作アプリを、買い替えたスマホに入れようとしたら、セキュリティが厳しくなっており、以前のようにインストールできない。

ネットで調べたら、build.gradleを以下のように修正して、ビルドするとインストールはうまくいった。

 buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
        debug {
            applicationIdSuffix ".debug"
            debuggable true
        }
        releaseDebugKey { // releaseの設定を使用
            initWith release
        }
    }
    signingConfigs {
        releaseDebugKey {
            initWith debug
        }
    }

最新OSでは、内蔵ストレージへのアクセスにもいろいろ制限がかかっているので
以下のリンクを参考にコードの書き換えが必要だった。


2022年9月25日日曜日

数年前作成したグループウエアをGCEでためしてみた。

 古いシステムを動かしてみた。けっこう大変だった。

・JavaのバージョンをJava8にしないとだめだった。Tomcat9は使えたが。

・Mysqlの仕様変更があり、SSH上では、rootが作成できず、適当なユーザー名を作って、それに権限を与えることでなんとか動かせた。

やはり、一筋縄ではいなかようだが、時間かければなんとかなるということ。

gce インスタンスでTeraterm使えず

鍵生成をいろいろな方法で試してみたり(ユーザー名、鍵の形式、GCEの権限内容等々) 

いろいろ試行錯誤してだめだった。困っていたところ、

こちらの情報によると、インスタンス内のOSがSSHに厳しくなっているのが原因らしい。サイトの情報をもとに設定したら、使えるようになった。

2022年9月24日土曜日

GCEでWinSCPを使う

 GCEのインスタンスにファイルを転送するためWinSCPを使えるようにしてみた。秘密鍵、公開鍵の扱いに不慣れなので、いろいろ勉強になった。

はまったところ:
・秘密鍵を作成したときに、ローカルPCでのユーザー名がファイルの中に情報として入ってしまうようで、WinSCPでリモートにアクセスする際のユーザー名は、リモートのユーザー名ではなく、あくまでローカルPCでのユーザー名にしないとだめだった。基本的なことのようだが、今まで知らないでいた。
・WinPCは、直接秘密鍵が利用できず、.ppkなる拡張子のファイルに変換する必要があった。
・ポートは、セキュリティ上のこともあり外部からのアクセスでは標準の22を使わないことにした。インスタンスの中のsshサーバの設定には、
 port 22
 port 任意のポート番号(/etc/ssh/sshd_config)
のように2つ並べて置き、リモートからは22以外のほうを使うことにした。ルータとインスタンスのファイアーウオールの設定もそれにあわせて追加する必要がある。

いろいろなサイトを参考にさせていただいた。

・Dos Promptからもsshコマンドを使って手軽に確認もできるようだ。(秘密鍵生成などもできたり)
 ssh サーバアドレス(ホスト.ドメイン名もok) -i 秘密鍵ファイル名 -p 任意のポート番号

いろいろと手間はかかるようです。

2022年9月23日金曜日

GCEのインスタンスをつくってみた

 Herokuクラウドの無料枠もなくなったので、まだ無料枠が残っているGCEを使ってみた。

インスタンスの使い方がわからず、とまどったが、ネット上の情報に助けられる。まず、プロジェクトを作成する必要がある。ここで、適当に北米など選んでしまい、あとで、東京もあることに気づき、やり直すことに。ドメインは、すでに持っていたものを使い、DNSの設定なども必要に、TXT,Aレコードなどを追加していった。これに、今後はさらに、SSL化のために、証明書の発行なども必要になってきたり、Tomcatを使う予定なので、ポートの変換など、いろいろ手間がかかりそうだ。

 プロジェクトのあとは、インスタンスを作成、これがDockerのような仮想サーバなのだろう。OSや、CPUも選べるし、柔軟なカスタマイズができそう。そのぶん、設定項目が多くなってしまうが。

 つぎに、ターミナルがブラウザで表示なるので、てっきりここで、インスタンスの中を覗けるものだとだと勘違いしていた。何度か、SSHやApacheの設定を挑戦しても、外からアクセスできなかったので、おかしいなと、ルータのパケットフィルターやら、サーバのファイアーウオールやら、Apacheのポート変更やら、試行錯誤繰り返した。それでもうまくいかない。

 それもそのはず、インスタンスは、すぐ下のターミナルで操作するのでなく、「SSL」という小さなボタンをクリックすることで、それぞれのインスタンスの中をSSLで覗くことになるのだった。これに気づくまで、だいぶ時間がかかってしまう。ようやく、外からHTTPにアクセスできるようになる。

2022年9月22日木曜日

タッチセンサー+Arduino Uno+Dfplayer  シリアル通信で動かしみた


タッチセンサ 音楽プレーヤを作ってみました。

使い方:
①Mp3ファイルの準備
01~05のフォルダにそれぞれ、001.mp3~003.mp3の曲を入れておく
98のフォルダには、001.mp3に「音を小さくしました」、002.mp3に「音を大きくしました」という音声をいれておく。
99のフォルダには、001.mp3に「1番目のフォルダに切り替えました」のような音声を入れておく。これを5番まで作成。
②ボタンを押すと、フォルダが切り替わる。タッチセンサ3つに、3曲割り当てられる。
タッチセンサを押さないと、フォルダ切り替えはできないようにしてある。
③ボタンを押しながら、左側のタッチセンサに触ると、音量を下げられる。右側のタッチセンサに触ると、音量を上げられる。

arduinoのスケッチ

#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"
SoftwareSerial mySoftwareSerial(10, 11); // RX, TX
DFRobotDFPlayerMini myDFPlayer;
//void printDetail(uint8_t type, int value);
  const int SENSOR4 = 4;
  const int SENSOR5 = 5;
  const int SENSOR6 = 6;
  const int DIN_PIN = 7;
  int foldernumber=1;
  bool cflg=false;
void setup()
{  
  pinMode( DIN_PIN, INPUT_PULLUP );
  pinMode(SENSOR4, INPUT);
    pinMode(SENSOR5, INPUT);
      pinMode(SENSOR6, INPUT);
  delay(1000);
  mySoftwareSerial.begin(9600);
   if (!myDFPlayer.begin(mySoftwareSerial)) { 
    while(true);
 }
  myDFPlayer.setTimeOut(500); 
  myDFPlayer.volume(15); 
  myDFPlayer.EQ(DFPLAYER_EQ_NORMAL);
   myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);
}

void loop()
{
  if (digitalRead(SENSOR4)==HIGH) {
   myDFPlayer.playFolder(foldernumber,1 );  
    cflg=false;
  } 
  if (digitalRead(SENSOR5)==HIGH) {
   myDFPlayer.playFolder(foldernumber,2 );  
    cflg=false;
  } 
  if (digitalRead(SENSOR6)==HIGH) {
   myDFPlayer.playFolder(foldernumber,3 );  
    cflg=false;
  } 
   delay(1);

  if(digitalRead(DIN_PIN)==LOW ){
   if (digitalRead(SENSOR4)==HIGH) {  
      myDFPlayer.volumeUp(); 
      myDFPlayer.playFolder(98,2 );  //ageru saisei
      cflg=false;
   }else if(digitalRead(SENSOR6)==HIGH){
      myDFPlayer.volumeDown(); //Volume down
      myDFPlayer.playFolder(98,1 );  //sageru saisei 
      cflg=false;
   }else if(!cflg){        
     foldernumber=rand() % 5 + 1;
     myDFPlayer.playFolder(99,foldernumber ); //foldernumber onsei saisei
     cflg=true;
   }
  }

}

2022年9月21日水曜日

Dfplayerをarudunoのserial通信で制御

 Arduino Unoだと、上手く制御できそうなことは、わかったが、実際の組み上げにはいくつか、注意が必要だった。IOTの慣例?みたいなものがあるかも。知っている人にとってはどうということないことなのかもしれないが。

・電源は、Unoを経由せず、5v電源に繋がないと、安定しなかった。

・USB経由のserial通信は、pcと繋がないなら不要なので、コードから削除した。

・Delay関数で、dfplayerとの、通信は、立ち上げ後、1secしてから、開始させてみた。

・Net上のライブラリを使ったが、フォルダとmp3ファイルどちらも、0を先頭につけ桁数を揃える必要がある。(フォルダ、ファイル指定して再生する場合)

シリアルだと、2つのボタン押しに機能を持たせたり、カスタマイズの幅が広がり、なかなかいい。

Win11で慣れるまで少し時間がかかったこと

 Win11になり、よく使うメニューが変更になりとまどう。
 ファイル名の変更がわからず、「その他のオプション表示」から探していたが、よく考えたら、けっこう使用頻度が高いはずなんだけど面倒だなと不思議に思っていた。調べてみたら、コピペ同様、小さなアイコンで操作するといいということがわかった。他にも、F2キーを使う等の方法もあるようだ。
 ほかに、慣れる必要あるものとして
・コントロールパネルの出し方は、スタートボタンから検索Boxにconなどと入力すると出てくる。このへんは、Linuxっぽくなってきた感じがする。
・スタートボタンは、左クリックのメニューもよく使う。コンピュータの管理、ディスクの管理。結局、Winxpや7のときから使っていたようなものの場所が、win10,win11と変わるたびに変更されていくので、そのたびに、メニューをさがすのに時間がかかるようになってしまい、非効率。なんらかの法則的なものがあるとか、メニューの新たな探し方を追加で入れてもらうにはいいのだけど、変更は、やはりきつい。できれば、あまり変えないでほしいというのが、素直な感想。
・Linuxなども、ネットワークの設定コマンドがバージョンにより変わってきたりもするが、基本的なCUIコマンドが変わることはほとんどない。CUIも覚えるのは大変だが、いったん覚えれば、いつまでも使えるので、WinとLinuxそれぞれ一長一短があるといったところか。

 技術というのは、できれば、古い形式にも対応できるようにしながら、新しいものを追加していければ理想なのだろうけど。
 地デジへの移行の際も、いきなり古いアナログTVは使えませんではなくて、古いTVでも対応できる新しい電波形式にするとか(アナログからデジタルに一気に変更でなく、アナログにデジタルを追加したようなものを考えるとか)してもらえば、利用者に優しいものになったのだろうけど。。。
 たしか、FM放送は最初モノラル電波で、途中からステレオ電波になったはずです。そのとき、古いモノラルのラジオでも、ステレオの電波をモノラルで受信できるような形式に工夫されていたはず。。


2022年9月20日火曜日

gession 回覧の返信可能に

 以前から思っていたのですが、グループセッションの回覧機能に返信機能があるといいなと考え、Jqueryなど使い実装してみた。けっこう時間はかかったが、なんとか完成した。コンパイルせず、JSPだけでなんとかできた。

 ただし、ユーザーIDの扱い方がよくわからず、全角の氏名を使ってデータを扱うことにした。簡易的な方法なので、同じ職場にまったく同じ漢字の氏名の人がいると使えません。なんらかの形で文字を微妙に調整するとかする必要があります。

 でも、よく考えたら、同一漢字のままでグループウエアを運用することはないでしょう、おそらく運用上は部署名をつけるとかすると思うので、あまり関係ないかもしれませんが。


cir020.jsp
以下抜粋です。HTMLタグに必要なID属性なども追加必要です
<!-- 追加2022.9.19 -->
  <html:form styleId="cir010Form" action="/circular/cir010">
    <input type="hidden" name="CMD" value="search">
    <input type="hidden" name="reply_name" id="reply_name" value="">
    <input type="hidden" name="reply_title" id="reply_title" value="">
    <input type="hidden" name="reply_naiyo" id="reply_naiyo" value="">
  </html:form>

<!-- 追加2022.9.19 -->
<script>
$(document).ready( function(){
     setTimeout(function(){ 
          document.getElementById( "reply_name" ).value=document.getElementById( "hassin_name" ).textContent; 
           document.getElementById( "reply_title" ).value=document.getElementById( "reply_title_src" ).textContent;
           document.getElementById( "reply_naiyo" ).value=document.getElementById( "reply_naiyo_src" ).textContent;   
     },100);
    });
</script>
cir040.jsp
<%
String reply_title = "RE:"+request.getParameter("reply_title");
String reply_naiyo = "\n*********************Original Message*****************"+request.getParameter("reply_naiyo");
%>
<span id="reply_name2">
<%=request.getParameter("reply_name")%>
</span>


<!-- 追加2022.9.20 -->
<script>
$(document).ready( function(){
 
    setTimeout(function(){     
        var functinBtnName = $(".cir_send_sel_btn").attr('id');
        var paramStr = "CMD=getInitData";
        paramStr += getNowSelUsr();
        getSelAtesakiData(paramStr, functinBtnName, 0);             
    },100);    
        
    setTimeout(function(){     
        /* テンプレートポップアップ */
        $('#atesakiSelPop').dialog({
            autoOpen: false,  // hide dialog
            bgiframe: false,   // for IE6
            resizable: false,
            height: 0,
            width: 0,
            modal: true,
            overlay: {
              backgroundColor: '#000000',
              opacity: 0.0
            },
            buttons: {
              閉じる: function() {
                  $(this).dialog('close');
              }
            }
        });       
    },100);


    setTimeout(function(){     
      const list = document.getElementById('cmn120SelectLeftUser')
       const options = list.options
       Array.from(options).forEach(function(option) {
            if (option.label.trim() == $('#reply_name2').text().trim() ){
          option.selected=true         
           }

      }); 
       },300);
    
    setTimeout(function(){    
       var paramStr = "CMD=addUserData&";
           paramStr += getFormData($('#atesakiSelForm'));
           getSelAtesakiData(paramStr, $('#funcBtnName').val(), $('#funcBtnKbn').val());    
       },400);
    
    setTimeout(function(){     
    drawPopUsr();
    },500);
     
   });
</script>





2022年9月17日土曜日

Django 覚書14 WARNINGS: ?: (urls.W005) URL namespace 'admin' isn't unique. You may not be able to reverse all URLs in this namespace

 https://stackoverflow.com/questions/47933278/django-project-namespace-admin-isnt-unique を参考にさせていただきました。

path('admin/', admin.site.urls)を重複して、urls.pyに指定していたのが原因だった。Top階層のurls.pyのみに指定すると、解決。

2022年9月15日木曜日

Sqlite dump backup restore & 初期化

SQLiteのバックアップと復元は、こんな感じでできる。
backup
sqlite3 db.sqlite3
sqlite> .databases
sqlite> .output /dirname/test.dump
sqlite> .dump table_name
restore
% rm db.sqlite3
% sqlite3 test.dump < test.dump
****************
初期化したいときは、各アプリのmigrationsフォルダとdb.sqlite3をするといいという説明のサイトがあったので、実際やってみたが、うまくいかない。
別のサイトの情報では、migrationsフォルダの中の_init_pyは残して、他は削除とあった。この方法だとうまくいった。と、思ったら、エラーメッセージが出て、0001_initial.pyが必要という指示が出る場面があった、指示通りバックアップからファイルを追加したら、解決したというものもあった。微妙に調整が必要な場合もある?ようだ。そういうことに備えて、migrationsも、バックアップとってから削除したほうがいいかもしれない。

2022年9月11日日曜日

Django 覚書13 スクエアをsandboxからproductionに切り替えるにあたって

※View内のenviroment切り替えは、environment=request.site.sitedetail.production_sandbox

のような形で、adminのサイトページにSelectコントロールを追加し、sandboxとproductionの切り替えをすぐできるようにした。

ネット上のマニュアルを翻訳してみた。***********

Follow the steps to open the Developer Dashboard, but this time choose Production mode and copy the production application ID and access token.手順に従って開発者ダッシュボードを開きますが、今回は本番モードを選択し、本番アプリケーション ID とアクセス トークンをコピーします。

Update the domain string in the JavaScript reference from sandbox.web.squarecdn.com/v1/square.js to web.squarecdn.com/v1/square.js.JavaScript リファレンスのドメイン文字列を sandbox.web.squarecdn.com/v1/square.jsからweb.squarecdn.com/v1/square.js に更新します

The Web Payments SDK requires a valid application ID to return a payment token. Update the code by providing your production application ID.Web Payments SDK では、支払いトークンを返すために有効なアプリケーション ID が必要です。本番アプリケーション ID を指定してコードを更新します。

 In the "Configure the backend with your access token" section, you provided a Sandbox access token. Replace it with the production access token.「アクセス トークンを使用してバックエンドを構成する」セクションで、サンドボックス アクセス トークンを指定しました。これを本番アクセス トークンに置き換えます。

If you want to test the application in a production environment (squareup.com), you must use an actual payment card. Note that Square actually charges payment cards in production. Therefore, if you must test in production, charge minimum amounts.本番環境でアプリケーションをテストする場合 ( squareup.com)、実際の支払いカードを使用する必要があります。Square は実際に本番環境で支払いカードに課金することに注意してください。したがって、本番環境でテストする必要がある場合は、最小限の料金を請求してください。


Django 覚書12 Pythonのmap filter等の使い方で注意が必要なこと

 スクエアのサブスクリプションのリストには、カスタマーIDが表示されるが、これをアプリ内のユーザー名と紐づけする方法を考えてみた。簡単そうだが、意外にはまってしまった。結果的には、以下のようにすることで解決できたが、ここに至るまでは、試行錯誤が必要だった。

<View側>

usertmpl3=list(map(lambda ob:{'customerid':ob.customerid,'username':ob.username},User.objects.all()) )          

srclst=list(filter( lambda ob: ob.get('canceled_date',"")=="",list(result.body['subscriptions'])))

subscriptions=list(map( lambda ob : {'subsc':ob ,  'cid':next( filter(lambda ob2: ob2['customerid'].strip() == ob['customer_id'].strip() ,usertmpl3),{'customerid':"",'username':"削除"})['username'] } ,srclst ))

sng= datetime.datetime.strptime(nen1, "%Y/%m/%d")
eng=  datetime.datetime.strptime(nen2, "%Y/%m/%d")
sbdt=list(filter(lambda sd:datetime.datetime.strptime(sd['subsc']['start_date'], '%Y-%m-%d')>=sng and datetime.datetime.strptime(sd['subsc']['start_date'], '%Y-%m-%d')<= eng,subscriptions))          

注意点:usrtmpl3、srclstいずれも最後にlistを適用してある。こうしないと、うまく動作しない。(filter()関数の戻り値はgeneratorオブジェクトという記述がネット内にある。)

まわりくどい式になってしまった。もっとスマートな方法がありそうだが。値が存在しないときに「削除」という表示にしたかったので、nextを使ってみた。

<HTML>
sbdt=response.sbdt;
$('<p style=font-weight:bold;>ユーザー名  サブスクリプションID ~</p>').appendTo('.result');
for (var i in sbdt) {  
   $('<p>'+sbdt[i]['cid']+" "+sbdt[i]['subsc']['id'] ~ +'</p>').appendTo('.result');  }
       

2022年9月10日土曜日

高血圧の基準と降圧剤ビジネス

 https://president.jp/articles/-/61331?page=4

 高血圧の基準は年々きびしくなっている。なぜだろう?と思うことがあったが。何が本当なのか、よくわからない。高すぎても、低すぎてもよくないということは、確かかもしれない。

2022年9月7日水曜日

スイフトのエンジンが安定しない。イグニッションコイル交換

 10万kmはもつといわれているイグニッションコイルだが、なぜか、14万kmで2回目の交換。今回は寿命がくるのがはやい。プラグもまだなんとかなるはずなんだけれど。とりあえず、交換したら快調になった。あまりケチらず、少し高いイグニッションコイルを購入した。

Django 覚書11

 スクエアを利用してみる。

pip install squareup

APIの説明が膨大。和訳して読みこなす。

Ajaxで、サーバを動作させて(Viewに記述)なんとかできそうだ。

様々なIDが必要でかなり手間はかかるし、いろいろ工夫も必要なようだ。


2022年8月28日日曜日

Django 覚書10

N+1問題のチェックのため、debug toolをインストールしたがエラー

https://stackoverflow-com.translate.goog/questions/72777378/django-debug-toolbar-baseconnectionhandler-all-error?_x_tr_sl=en&_x_tr_tl=ja&_x_tr_hl=ja&_x_tr_pto=sc

どうやら、バージョンを古くしてやるといいということだった。これで解決。

2022年8月27日土曜日

Django 覚書9 delete

クラスで試したがなぜかうまくいかない。 クラスのDeleteViewで削除する例は多いが、関数を利用したものが少ない。

関数だと、こんなふうにしたところ、うまくいった。


@login_required
def mcsmain_delete(request,pk):
    template_name = "mcsmain/mcsmain_delete.html"
    mcsmain = get_object_or_404(Mcsmain, pk=pk)
    if mcsmain.created_by_id != request.user.id:
        return HttpResponseForbidden("このメッセージの削除は許可されていません。")   
    if request.POST:
        mcsmain.delete()
        return redirect('/')
    return render(request,template_name) ←ここで、pkを渡さなくても、postには支障ないようだ。このへんがわかりずらい。

***mscmain_detail.html
<a href="{% url 'mcsmain_delete' mcsmain.id %}">削除</a>

***mscmain_delete.html
<form method="post" >
 {% csrf_token %}
    <p>削除していいですか?</p>
    <input type="submit" value="削除する">
</form>

2022年8月20日土曜日

Django 覚書8

テンプレートを、登録と編集で2つ用意したが、編集用がなぜか、viewで、テンプレート指定しているが存在しないというエラー、存在しているのだけれど。
仕方なく、兼用して、formの中身でタイトルだけ切り替えてみた。
formからの取り出し方は、form.nicknameだけではだめで、valueを追加する必要があった。


{% extends "base.html" %}
{% load django_bootstrap5 %}
{% block main %}
 {%if form.nickname.value != "" %} 
  <h2>プロフィールの編集</h2>
 {% else %} 
 <h2>プロフィールの登録</h2>
 {% endif %}
<form method="post" enctype="multipart/form-data" class="p-4 m-4 bg-light border border-success rounded form-groups">
    {% csrf_token %}
    {% bootstrap_form form %}
    {% bootstrap_button button_type="submit" content="保存" %}
</form>
{% endblock %}

2022年8月17日水曜日

Django 覚書7

 ファイルサイズ制限をする方法を調べてみた。(画像を圧縮する実装も、それはそれで大変なので、ファイルサイズ制限にしてみた)

https://www.sea2800.com/?p=513

Modelのほうに、コードを入れるほうがいいようだ。

 community_photo=models.ImageField("コミュニティ画像",upload_to='community_photos/',null=True,blank=True,validators=[file_size])

def file_size(value):
    limit = 500000
    if value.size>limit:
        raise ValidationError('画像サイズは、500KB以下にしてください.')


ただ、Viewでは関数を使っていたので、若干の注意が必要だった。

@login_required
def community_create(request):
    if request.method == "POST":
        form = CommunityForm(request.POST,request.FILES) 
   #defのときは、やはりrequest.FILESが必須のようだ。これがないとうまくいかない。
        if form.is_valid():
            com=form.save(commit=False)
            com.community_photo=request.FILES.get('community_photo')
   .....

2022年8月16日火曜日

Djanog 覚書6 基本のまとめ

 とくにViewとFormあたりで、関数なのか、クラスなのかで、いろいろごちゃまぜになりやすい。関数のほうが、カスタマイズしやすいので、Formと一緒に基本的なことをまとめてみた。

#FORM

class CommunityForm(forms.ModelForm):     
 community_introduction = forms.CharField(widget=forms.Textarea(attrs={'placeholder':'紹介文...'}), max_length=512,label="コミュニティ紹介")       

        model=Community
        fields={'id','community_name','community_photo','community_introduction'}

#VIEW
@login_required
def community_create(request):
    if request.method == "POST":
        form = CommunityForm(request.POST)
        if form.is_valid():
            com=form.save(commit=False)
            com.community_photo=request.FILES.get('community_photo')←画像はこの処理が必要
            com.created_by=request.user ←念のため入れる?
            com.save()
            return redirect(community_detail,pk=com.id)
    else:            
            form = CommunityForm({'created_by':request.user}) ←正しくは、このようにするとOk
            #form.created_by= request.user ←あらかじめ、データを入れておくために、最初、これで試したがだめだった。
なお、CommunityFormのほうでは、fieldにcreated_byは入れないことで表示はしない。けれど、Communityのモデルの処理は行ってくれる。このへんに、注意が必要かも。
    return render(request,'accounts/community_create.html',{'form':form})



@login_required
def community_update(request, pk):
    com = get_object_or_404(Community, id=pk)
    if com.created_by.username != request.user.username:
        return HttpResponseForbidden("この編集は許可されていません。")
    if request.method == "POST":
        form = CommunityForm(request.POST, instance=com)
        if form.is_valid():
            post=form.save()
            post.community_photo=request.FILES.get('community_photo')←画像はこの処理が必要
            post.created_by=request.user ←念のため入れる?
            post.save()
            return redirect('community_list')←ここは、detailでもいいかもしれない
    else:
        form = CommunityForm(instance=com)
    return render(request, 'accounts/community_update.html', {'form': form})

※上記の方法だと、Updateのときに、画像データが消えてしまう。
これを避けるには、以下のように修正するといいようだ。

@login_required
def community_update(request, pk):
    com = get_object_or_404(Community, id=pk)
    if com.created_by.username != request.user.username:
        return HttpResponseForbidden("この編集は許可されていません。")
    if request.method == "POST":
        if not request.FILES:
            request.FILES['community_photo'] = com.community_photo #更新時画像保持
        form = CommunityForm(request.POST, request.FILES, instance=com) #blank=Turue,null=Trueだと、request.FILESが必須とのこと
        if form.is_valid():
            post=form.save()
            post.community_photo=request.FILES.get('community_photo')
            post.created_by=request.user
            post.save()
            return redirect('community_list')
    else:
        form = CommunityForm(instance=com)

    return render(request, 'accounts/community_update.html', {'form': form})



Django 覚書5

 サイトのページで設定を操作するには、最初、テキストファイルにでも保存するのかと思っていたが、あまりそういう方法は取らないようで、やはり、データベースに置くようだ。

https://blog.narito.ninja/detail/104

上記サイトを参考にさせていただいた。これだと、どのページからでも、グローバルでrequest.site.sitedetail.プロパティ というような感じで読み取れるので、非常にありがたい。また、管理サイトで、編集もできる。

 早速、サイトの中でも変更の可能性がありそうな、style変更(colorなど)や説明文等に利用させてもらった。

2022年8月15日月曜日

Django 覚書4

 今回は、フロントエンドの一部をELMでかいてみた。しかし、ちょっとした連係ミスでこまることもある。ELMでブートストラップを使って、ボタンを表示していたが、これが、PCサイズの指定なので、Djangoで、レスポンシブがうまく動作しない。スマホでの表示が、PC表示から切り替わらないという現象が起きた。面倒なので、ELMの表示は、Bootstrapは使わず、すべて、Djangoのほうで統一することにした。

 さらに、やっかいなのが、ブラウザには画像だけでなく、JSのキャッシュも残っているということ、もちろんELMもJSなので、ELMをコンパイルしたはずなのに、すぐ反映してくれない。仕方ないので、ブラウザのキャッシュを削除したら解決。

Django Test 覚書3

 Djangoでは、Testの必要性を感じ始め、少しずつ取り組んでいる。

初歩的ミスから

@login_required
def mcsmain_detail(request, mcsmain_id):
    mcsmain = get_object_or_404(Mcsmain, pk=mcsmain_id)
    comments=....
    return render(...

class SnippetDetailTest(TestCase):
    def setUp(self):
        self.user = UserModel.objects.create(
            username="test_user",....
   ①ここに

    def test_should_use_expected_template(self):
        response = self.client.get("/mcsmain/%s/" % self.mcsmain.id)
        self.assertTemplateUsed(response, "mcsmain/mcsmain_detail.html")

login_requiredなので、エラーが発生、   self.client.force_login(self.user)をテストの①の中に入れる必要がある。
    

2022年8月14日日曜日

Django 覚書2

 ちょっとしたことで、だいぶ時間がかかってしまった。

  {% if request.user.id==item.created_by.id %}では、だめで

  {% if request.user.pk == item.created_by.pk %}が正解だった。テンプレートには、まだなれていない。

2022年8月12日金曜日

Django 覚書

 Djangoの参考書も読んだが、それだけでは実際のシステムを作り上げる際にいろいろな壁にぶつかってしまう。結局、ネットで情報を仕入れたり、工夫しながらやっていくしかない。最近、いくつかきづいたことをまとめてみた。

・メール送信は、必ずしもサードパーティがいいとも限らない。2,3試したがどれも、自分の環境ではうまくいかず、結局、Djangoの基本機能を利用してうまくいった。(フォームメールなども含めて、そのほうがいいようだ)前回の投稿参照のこと

・画像ファイルのアップロードも、圧縮したい。これは、stdimageためしたが、うまくいかない。Djangoのクラスをうまく継承している、imagekitをためしてようやくうまくいった。

 Imageモデルを作成して、それをViewの中で通常の使い方ができる。くせがない感じだ。

 image=Image.objects.all().filter(taken_by=profile_id).first()のように

マッチングサイトの足あと機能は、こんな感じでmap活用してなんとかクリア

class FootprintListView(LoginRequiredMixin,ListView):    
       template_name="accounts/footprint_list.html" 
       paginate_by=4       
       def get_queryset(self):         #なぜか、これを入れないとエラー、このへんが
                    return uquery(self,"" )      #まだ 勉強不足
       def get_context_data(self):
          context = super().get_context_data()
          flist = Footprint.objects.filter(looked=self.request.user) 
          #object_list=uquery(self,"" )
          iobList=map( lambda ob: {'usr':ob.look
                                   ,'img':Image.objects.all().filter(taken_by=ob.look.id).first()
                                   ,'footprintThanksSend':Footprint.objects.all().filter(look=ob.look,looked=self.request.user ).first()
                                     }  ,flist)   
          context['iobject_list']=iobList
          context['cuser']=self.request.user
          context['count']=len(list(iobList))
          return context
・「足あとありがとう」(自分のプロファイル見てくれてありがとう)の機能は、意外と基本的なところで、つまづく。①~③のところは、どうということのないところだが、これを思いつくまでだいぶ時間がかかった。画面のフォームを通して、値を入れていくコード例はたくさんあるが、このように、直接値を入れることは少ないので。

@api_view(['GET'])
@permission_classes([IsAuthenticated])
def footprint_thanks(request,profile_id):
    if request.method == 'GET':           
       thanks_from = request.user.id  # miraretahito 
       thanks_to=User.objects.filter(id=profile_id)[0] #gazo mitahito
       obj=Footprint.objects.filter(look=thanks_to).first() ①
       obj.thanks=True ②
       obj.save()  ③
       return render(request, 'accounts/footprint_thanks.html', {'thanks_to':obj.look})

2022年8月8日月曜日

django リンククリックでユーザー登録するためのメール配信

サードパーティのアプリもあったが、なかなか組み込みが難しかった。djangoのメール配信機能があるので、それを使ってみた。

ポイントは View と 環境変数

@api_view(['GET'])
@permission_classes([IsAuthenticated])
def mail_send(request,profile_id):
    if request.method == 'GET':     
       token=hashlib.sha256((str(profile_id)+"ここには適当な文字をsaltとして入れる").encode('utf-8')).hexdigest()
       if settings.DEBUG==True:        url="http://"+settings.ALLOWED_HOSTS[0]+":8000/accounts/mail_check/"+str(profile_id)+"/?token="+token 
       else:        url="https://"+settings.ALLOWED_HOSTS[1]+"/accounts/mail_check/"+str(profile_id)+"/?token="+token #0がlocal環境、1が2つめ deploy環境 から取得する。      
       subject = "メール登録について"
       message = "メール登録のためのリンク:"+url
       from_email = settings.EMAIL_HOST_USER  # 送信者
       to_email=User.objects.filter(id=profile_id)[0].email
       recipient_list = [to_email]  # 宛先リスト
       send_mail(subject, message, from_email, recipient_list)
       return render(request, 'accounts/mail_send.html', {'to_email':to_email})

@api_view(['GET'])
def mail_check(request,profile_id):
    if request.method == 'GET':     
       token=hashlib.sha256((str(profile_id)+"ここは適当な文字をsaltとして入れる").encode('utf-8')).hexdigest()
       if token==request.GET.get("token")  :
            tokenflg=True
        #ここで、DBのフラグ変更
            cdt=get_object_or_404(User,pk=profile_id)
            cdt.is_kaiin=True
            cdt.save()
       else :
            tokenflg=False
       to_email=User.objects.filter(id=profile_id)[0].email
       return render(request, 'accounts/mail_check.html', {'to_email':to_email,'tokenflg':tokenflg})

***パラメータの取得方法は、request.tokenかと思ったが、そうではなく、request.GET.get("token") だった。このへんは、慣れていくしかない。

settings.py
DEBUG = os.getenv('DEBUG',True) #deploy環境ではDEBUG環境変数をFalseに
ALLOWED_HOSTS = ['localhost','ここに公開サーバドメイン']

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# 環境変数にしておけば、セキュリティも上がり、ローカルとDeploy環境の切り替え負担もない いちおう、ディフォルトはローカルにしてみた
EMAIL_HOST = os.getenv('EMAIL_HOST','smtp.gmail.com')
EMAIL_PORT = os.getenv('EMAIL_PORT',587)
EMAIL_HOST_USER = os.getenv('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = os.getenv('EMAIL_HOST_PASSWORD') 
EMAIL_USE_TLS = True

**その後、この方法だと、レンタルサーバによっては、OSから環境変数がうまく取得できないことがあることが判明、そこでdjango-environというものを使わせていただいた。これだと、うまく動作してくれた。

**さらに、追加情報
 ローカルからはだいじょうぶだったが、公開先のサーバでは、djangoからのメール送信元がwebmaster@localhostとなり、エラーが発生する。 
 https://teratail.com/questions/255401 の情報によれば、DEFAULT_FROM_EMAIL に、送信元をきちんと設定しておくことで、解決した。いろいろ、知らない情報も、ネットでググるといいようだ。

2022年8月5日金曜日

django Formで外部キーの内容の選択範囲をフィルタリングするには

https://qiita.com/44d/items/897e5bb20113315af006 を参考にさせていただいた。

マッチングアプリで、「いいね」をお互いに交換できた人のみ、選択できるようにしてみた。
ok_listは、前回考えたアルゴリズムをそのまま利用した。
ポイントは、 form.fields['receiver'].queryset = User.objects.filter(id__in= ok_list(request)) の部分。


@login_required
def dmessage_new(request):
    if request.method == 'POST':
        form = DmessageForm(request.POST)
        if form.is_valid():
            dmessage = form.save(commit=False)
            dmessage.sender = request.user
            dmessage.save()
            return redirect(dmessage_detail, dmessage_id=dmessage.pk)
    else:
        form = DmessageForm()    
        form.fields['receiver'].queryset = User.objects.filter(id__in= ok_list(request))
    return render(request, "dmessages/dmessage_new.html", {'form': form})

def ok_list(request):
          like_list = Matching.objects.filter(  Q(approaching__username__icontains=request.user) )
          liked_list = Matching.objects.filter(  Q(approached__username__icontains=request.user) )
          return (like_list.values_list('approached',flat=True)).intersection(liked_list.values_list('approaching',flat=True))

2022年8月4日木曜日

古いソフトの実行

 win11にしたら、win10まで動いていた古いソフトが動かなくなる。vbrjp200.dllなど、何十年前のVBのランタイムだが、ついにこれだけで動かなくなってしまった。が、よく調べると、otvdmという便利なものがあった。うまく動作してくれた。

djangoをローカルネットでサーバーに

 windowsでdjangoを、ローカル内で使えるか試してみた。

・ファイアーウオールの受信ポート8000を開けてみた。

 ルータのフィルタリングも念のため、確認

これだけではだめだった。

・djangoのallow hostsは['192.....']の形式で設定

・起動は python manage.py runsrver 192.....:8000 とする

この2点をうっかりすると忘れやすい。

2022年8月1日月曜日

djangoでもpythonの関数型機能が役立つ

 マッチングの機能を作成してみた。DjangoのListViewで相手を選択する、選択されるのリスト。マッチしたユーザーのリストを取得するには、どうするかで、けっこうはまる。

ようやく解決方法をみつける。pythonのmap関数、ラムダ式が役立った。

  def get_context_data(self):
          context = super().get_context_data()
          like_list = Matching.objects.filter(  Q(approaching__username__icontains=self.request.user) )
          liked_list = Matching.objects.filter(  Q(approached__username__icontains=self.request.user) )

          context['like_list']=like_list
          context['liked_list']=liked_list
          tmplist=(like_list.values_list('approached',flat=True)).intersection(liked_list.values_list('approaching',flat=True))
          context['ok_list']=list(map( lambda ob: User.objects.get(id=ob) ,tmplist))
         
          return context

2022年7月30日土曜日

raspberry piのシステムイメージサイズを変更するには

 microsdカードは会社ごとに違うため、同じ32GBでも、ちょっとでもサイズが小さいとイメージを移すことができない。

サイズを変更するには、意外に手間がかかるようだ。

https://enable-ax.work/raspberry_pi/raspbian_backup/

https://jorublog.site/raspi-hdd-connect/

http://denshikousaku.net/reduce-raspberry-pi-img-file-to-write-on-smaller-micro-sd-card

https://jorublog.site/raspi-nas-samba/

上記のリンクを参考にさせていただいた。

imgファイルはこれまで、Windowsで作成していたが、raspiでもできるようだ。ただし、外付けHDDが必要だが。raspiの中で,imgファイルを縮小し、それをsambaで再度Windowsにもってきて、microsdに書き込んでみた。そして、最後にサイズを拡張。これで、sdカードのサイズ違いに悩まされることはなくなった。

2022年7月27日水曜日

dfPlayerをタッチセンサーで

これまで、ブレッドボードで試してきたが、だいぶ安定してきたので、下図のような配線でユニバーサル基板につくる予定



2022年7月26日火曜日

HFでチャット~VarAC~

HFでチャットできないものかと思っていたら、ありました。

そのうち試してみたい。URLリンクを送ることで、いろいろ画像等の交換もできそうだ。

http://blog.livedoor.jp/je3prm/archives/29059812.html

2022年7月24日日曜日

PCIのSATAで、SSDにUbuntuを入れるには

  Win11が原因なのかどうかわからないが、なぜか、SATA増設のためのPCIボードを購入したもののUbuntuが入らなかった。フォーマットがうまくいかない。OS起動が難しいようなネット情報もあったので、そのへんが原因なんだろうか。

 そこで、直接入れるのはあきらめて、VirtualBoxを試した。ところが、これもうまくいかない。そこで、Vmwareを試したら、なんとかうまく入れることができた。

スイフトのリモートキーDIY修理

  リモートキーが、たまに不調になることがある。電池交換しても変化ないときは、ボタンスイッチの接触不良が原因。キーOpenとCloseの2つのボタンのどちらかが、効きにくいときはたいがいそうである。

 ボタンスイッチのところの直径数ミリの皿状の金属片が、ずれたり、接触不良になっている。何度か、修理したので、だんだんコツがのみこめてきた。軽くサンドペーパーで接点を磨き、接点復活剤も使ったあと、金属片を固定したら上から両面テープでおさえた。今回は、ゴムカバーとくっつかないようにするため、さらにその上からセロテープを貼ってみた。いちおう、回復したがはたしてどのくらいもつか、様子を見ることに。

 

Django 画像表示でエラー

       <img src="{{ prof.profile_photo1.url }}" >で、.urlをつけないとエラーは出ないが、画像が表示ならない。.urlをつけるとエラーがでる。なぜだろうと、解決まで少し時間がかかる。仕方ないので、エラーメッセージで検索。

The 'image' attribute has no file associated with it.

https://qiita.com/ksan612400/items/620eed1518c9697fa26a 

英語理解力も、プログラミングには大切なようだ。.

  {% if prof.profile_photo1 %}

                <img src="{{ prof.profile_photo1.url }}" >

  {% endif %}

.urlを使うには、ファイルが存在しないとだめならしい。

                

2022年7月23日土曜日

Djangoの画像保存(viewの記述も要注意)

 djangoの画像保存処理は、viewで、ひと手間加える必要あるようです。

https://inglow.jp/techblog/django-image/を参考にさせていただきました。

if request.method == "POST":
        form = ProfileForm(request.POST, instance=user)
        if form.is_valid():
            post=form.save()
これだけでOkかと思いきや、画像ファイルの場合は、以下の2行を追加必要なようです。
            post.profile_photo1=request.FILES['profile_photo1']
            post.save()

その後、request.FILES['profile_photo1']は、ローカルではOkだったが、サイト上ではだめだったので、調べたら、request.FILES.get('profile_photo1')としないとだめとのことだった。そのように修正したところ、うまく動作しました。

今のインフレは、賃金アップにはつながらないらしい

 https://www.youtube.com/watch?v=ky30O6E8V6k

によれば、今のインフレは輸入原料(エネルギー、食糧)の高騰が原因なので、国内の賃金アップにはつながらないとか。消費増税と同じで、結局デフレ構造の誘因になるだけらしい。対策は、エネルギー多様化、食糧自給率アップのために、国がお金を使うことが大切だとのこと。ガソリン・電気、食費はアップしているけど、それが生産者の所得増につながらないということのようだ。

2022年7月20日水曜日

Elmでサウンド再生

https://github.com/kiridaruma/elm-port-test を参考にさせていただきました。

途中、省略している部分ありますが

Elm側: AudioP.jsにコンパイル
port module AudioP exposing (..)
port startSound: () -> Cmd msg
type alias Model =
    { msg: String  ,       .....          }
type Msg
    = Message String | Ans Int | ...

update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
    case msg of
       Message str -> ({model | msg = str}, Cmd.none)
       Ans num -> ({model | .....  }, startSound() )
       ....
view : Model -> Html Msg
view model = ......

Html側:
<!DOCTYPE html>
<html lang="ja">

<head>
    <script src="AudioP.js" async></script>
    <script defer>
        window.addEventListener('load', () => {
            const app = Elm.AudioP.init({ node: document.getElementById('target') })
            const audio = document.getElementById('audio')
            app.ports.startSound.subscribe(() => {
                audio.currentTime = 0;
                audio.play()
            })
    </script>
    <title></title>
</head>
<body>
    <div id="target"></div>
    <audio id="audio" src="test.mp3"></audio>
</body>
</html>


2022年7月17日日曜日

LPFの修正

 FT8で自作リニアを使ったら、終段を焼いてしまう。安いFETなので、スペアを多めに用意しておいたもので交換。 連続送信はご法度のようだ。このリニアはSSB送信を想定しているのかも。

 ついでに、Aliexpressで購入したLPFは、7MHzの動作がおかしかったので、そちらのインダクタンス(NanoVnaServerで)、キャパシタンス(格安測定器で)を測定。インダクタンスが予想より大きかった。1.3uHぐらいのはずだが、2uHほどあった。7MHzが抑制された原因はこれだろう。Qucsで、確認したちょうどよさそうな値になるように、巻き数を減らして調整した。格安測定器で測定したキャパシタンスは、測定ごとに変化してしまい、正確なところがよくわからないが、まあまあ近い値だろうとそのまま使うことにした。 本当は、複数の測定器で比べるといいのかもしれないが。

 Qucsのシミュレーションではうまくいったが、はたして、実際にこれでうまくいくだろうか。以前アップしたものを、再掲載。

 その後、残念ながら、リニア復活せず、だいぶ基板も傷んできたし、安いので再度キットを購入し、時間かけてゆっくりと最初から作ることにしたい。





2022年7月14日木曜日

自作リニアで移動局50W申請Ok

 自作リニアアンプで、変更申請し無事、申請が通った。IC-705用に作ったリニアアンプを使えることになった。数か月かけて、ちょっとずつ組み立てていったリニアアンプだが、移動だけでなく、固定でも利用していく予定。アンテナチューナはATU-100を利用することになりそう。

2022年7月5日火曜日

ワイヤレスマウスのフリーズ

 最近、マウスの動きが止まることがある。ワイヤレスマウスなので、スイッチを入れなおすと回復する。もしかすると、スイッチの接触不良(酸化による)かと思い、試しに接点復活剤をスプレーして様子を見てみる。今のところ、その現象は見られなくなったが。これで直ってくれれば、いいのだが。

その後:まったく、フリーズしなくなった。どうやら、接触不良が原因だったようだ。

2022年7月3日日曜日

ワイヤレスマイクの音声をWEB通信アプリへ

 タブレットのように、マイクもカメラも内蔵している端末でWEBカメラ通信を行うのは、手軽でいい反面、大きな会場などは拡声器を通した音声が反響が大きくどうしてもききとりにくい。 

 そこで、ワイヤレスマイクの拡声器のライン出力をPCやタブレットの音声入力へつなぐ方法を考えてみた。

 その際、問題になるのは内蔵のマイクとの切り替えだが、Ipadなどは、つなげてからアプリを立ち上げればOkなようだ。(マイクとスピーカを枝分かれされるケーブルなど必要)

 それに対して、Windowsは、設定>システム>サウンド>サウンドの詳細オプションの「アプリの音量とデバイスの設定」で、細かく変更できるようだ。ChromeブラウザでwebRTCなど行う場合は、ここでブラウザの音声入力を変更できるようだ。

2022年7月1日金曜日

非推奨PCにWIN11

 ついでに、core2に換装したdynabook L21 220C/WをWIN11にしてみた。

 WIN11のDVDから、中身をデスクトップにコピーして、sourceフォルダのappraiseres.dllを削除し、setup実行

 「セットアップでの更新プログラムのダウンロード方法の変更」をクリック>今は実行をしない 選択>次へで 進めるとうまくいくようだ。

dynabook L21 220C/W CPU換装、SSD化

 Celeron 900をCore2に変更してみた。

一回目、ヤフオクで動作未確認のT7250を試したが見事にはずれでした。動作せず。CPUなど、そんなに簡単に不具合出るものでないと勝手に思っていましたが、そうでもないようです。二回目、同じくオークションで見つけた動作確認済みT8100(対応できるのはQCKA、SLAUU、SLAYZ、Q8LB、SLAP9、SLAYP、SLAVJ、SLAP9、SLAYP)を入れてみたら、うまくいきました。いずれのCPUも送料入れて、1000円前後なので、だいぶ安くなっています。

 タッチパッドが動作しなくなったが、フラットケーブルの裏側のプラスチックがとれていたのが原因だった。両面テープで再度貼り付けたら、修復できた。

 SSDを入れ、メモリも4GBにすると、結構快適に使える。

2022年6月26日日曜日

raspi2 冷却

 毎年、秋になるとsdカードが不良になったり、暑い時期をすぎると不調になるraspiなので、できるだけ冷却を、ということで、CPUの上にサーマルシートを重ねて、その上に、不要になったCPUファンをのせてみた。そしたら、ファンは動かさなくても、まあまあ冷却作用はあるようだ。3~4度程度は下がっているかも。



2022年6月23日木曜日

dfplayerをタッチセンサーで操作

 MP3プレーヤモジュールのDFplayerをarduino  nano互換機で操作できないか、試してみた。UARTを使おうとしたが、なんとしてもだめだった。モジュールが純正でないため?かもしれないが、ネット上でもいろいろ情報あるが、だめという報告もあるようだ。

  →後日、純正のArduino Unoで試したら、シリアルでもOkだったので、やはりハードに完全な互換性がないことのようだった。

 そこで、抵抗値によって、操作できる簡易な方法もあったので、そちらで試したらうまくいった。いくつかのタッチセンサーモジュールの電圧をいったん、arduinoに入れて、出力をいくつか用意し2sc1815を通して、プレーヤに入れてやるが、そのとき、種々の抵抗値を入れたものにすることにした。リレーを使わず、トランジスタのスイッチング機能を使う感じ。本当は、トランジスタのベース電圧を変化させて、コレクタの抵抗値を変化させられないかと思ったのだけれど、Aruduinoのアナログ出力は、疑似アナログ電圧(PWM)なのでそれは、無理だったようだ。

 しかし、これもあまり安定した動作をしない。よくわからないが、電源をArduinoとDFplayerで、共用しているのもよくないのだろうか?

 結局、タッチセンサーモジュールから直接、トランジスタのスイッチング機能を使うことにした。このほうがシンプルで比較的安定した動作のようだ。Aruduinoは使わずじまいになってしまったが。あと、面倒なので種々の抵抗値を使う方法はとらないことにした。タッチセンサーは2個使用し、一個は1番のファイルを開始するために、もう一個は前の曲へ進めるため(長押しだとVol+)に使った。

 




2022年6月18日土曜日

wsl Ubuntuのバージョンアップ

 WSLのUbuntuを最新版にしてみた

https://zenn.dev/ryuu/articles/upgrade-ubuntu2204-wslを参考にさせていただく。

無事Ubuntu Ver22.04にすることができた。

cドライブにあると、SSDを使っているため、読み書きが激しいかと思い、HDDドライブに移動してみた。

win11インストール

  PCがSSDあたりが原因と思われるけど、デバイスエラーを起こすようになり、SSDだけでなく、マザボ、メモリ、CPUを11世代に交換した。しめて、3万円を超過したが、こんなところか。全部買い替えるよりはだいぶ安い。12世代は、高すぎるのでひとつ前ぐらいがちょうどいいようだ。ただ、インストールはけっこう時間がかかってしまった。マザボのピン折れ?で、交換に1~2週間待たされ、ディスプレイが反応しなかったり、プロダクトIDがProとHomeでは違う?のでとまどったり、12V電源に2か所接続というところがわからず苦労したり、。ただ、イメージバックアップは取りながら行ったので、それで少しは助かる。ようやく、動かすことができるようになる。6コア12スレッドというけれど、これを活用するには、ffmpegを並行実行させるときぐらいだろうか?活用方法もまだまだ、勉強不足。

 以前、使っていた第2世代のi7Cpuやメモリ、マザボは合計2000円ちょっとで、ハードオフで売れた。オークションならもう少し高く売れた?かもしれないが、今回は手間を考え楽な方法で処理。

2022年6月11日土曜日

PIC12F675をアダプタPICKIT3-KIT05に接続

 PICKit3.5にPICKIT3-KIT05経由で、PIC12F675を接続してみた。

ジャンパの設定、足の揃え方は、基板の印や説明を見るとわかるようになっていた。ただ、DIP8/14とあり、PIC10Fもあるので、PIC12はないのかと心配したが、DIP8/14はPIC8~14の範囲(10は除く)という意味らしい。←テスタでピンの接続を確認して、わかった。



別アプリの操作をC#で

 別のアプリを操作(ボタンクリックなど)するためのプログラムを作ってみた。

https://qiita.com/otagaisama-1/items/1fcb9b620084d7652a62

を参考にさせていただきました。Form1から利用するためのクラスを作成しました。

EnumChildWindowsProcの使い方がまだよくわかっておらず、似たようなメソッドを3つ作るという無駄もあります。それぞれ違う用途に使うことにしました。DRY原則もいいけれど、冗長性持たせたほうが、万が一コードをミスった時など、他のコードを参照できるので、いい点もある?

ウインドウのハンドルや、目的のボタンのハンドルを探すための工夫が必要なので、けっこ手間がかかります。ちょうど、Webスクレイピングをしている感覚です。

2022年6月4日土曜日

ipadタッチャー

 Ipadのタッチを、タッチセンサー経由で、できるようなものを作ってみた。

https://blog.goo.ne.jp/sasamory/e/154df917b89d0a6a0d9883bccc96d088

を参考にさせていただきました。スイッチでなく、TTP223のタッチセンサーを使ってみた。アマゾンで格安で入手できました。最初、タッチセンサのI/Oピンでリレーを動作できないか試してみたが、電圧が低すぎて(2V程度)でだめだったので、2SC1815を入れてみたらうまくいった。なお、TTP223は、感度良すぎて、不安定だったので、20pFのSMDコンデンサをC2の位置に入れてみたら、ちょうどよい感じになった。



2022年6月1日水曜日

久々にParagonでシステム復元したが、、一度失敗

 どうも、ブルースクリーンが出るようになったので、試しに、Paragonで

システムを復元してみたが、失敗。ディスクまるごと復元で試したのがよくなかったかと思い。再度、なぜか、Win10のインストールがうまくいかず、仕方なくWin7からWin10へと順にアップデート。今度は、パーティションのみ復元したらうまくいった。

 ただ、BIOSをいろいろいじってしまったためか、一度でうまくいかない。UEFIモードもOkにしたら、なんとか、復活してほっとする。はたして、ブルースクリーンは直ったか?これでもダメなら、マザボ交換しかないだろう。

2022年5月29日日曜日

夕方、バンパーの補修塗装

 シルバーの車を使っているが、冬の間に雪のかたまりにこすって、バンパーに傷がつき、簡単に塗装はしてみたが、どうも色がまわりと微妙に違い目立ってしまう。

 新聞紙などでまわりに散らないように養生テープでマスキングすると、境目がはっきりしてまい、失敗する。使わない方がいいようだ。

 もう一度、ぼかし剤で、塗料をとり、研磨、足付け、最低限の範囲にプラサフをさらっとかけ、そのあと、再度、さらっ、さらっと塗料をスプレー。ちょっとずつというのが、コツのようだ。境目をできるだけぼかすように。最初よりは、目立たない感じに仕上げることができた。あとは、クリア塗装とコンパウンドの予定。

 小さめの傷なら、タッチペンをぬって、しばらくたってかたまってから、ぼかし剤でならすとけっこうめだたなくなるようだ。

ATU-100のPICファームウエア更新


 ATU-100のPICのアップデートをしてみた。Ver3.0から3.2にしてみた。チューニングの最低を1Wに、最大を40Wにしてみた。

 最初、PICKIT3.5の使い方がわからず悩む。接続がうまくいかず、USB接続はシリアル通信のドライバでも必要なのだろうかと、調べるが、どうやら、そうでもない。ネット情報を見て、たまたま見つけた情報として、PICを載せているデバイスにも電源供給が必要だということがわかる。ATU-100には電源供給しないでも、アップデートできると勘違いしていた。ATU-100は12Vで、PicKitは5Vなので、大丈夫かと心配した。念のため、デバイスに低い電圧から試してみたが、丁寧にデバイスの電圧が不足しているとメッセージを表示してくれるので、徐々に電圧を上げて、結局12VでもOkだった。あとは、スムーズに進められる。今どきはコンパイラは無料のようだが、昔、PICのコンパイラを個人輸入でイギリスから1万円ぐらいで、英語に四苦八苦して購入したことを思い出す。(もっとも、今回はコンパイラを使う必要はないが)

 PicKitとATU-100の接続の仕方は、サイトで調べたら、下の写真のようにするといいようだった。

注:ATU-100の1番の端子の右側にねじれた赤い導線が見えるが、これは、Autoの設定用の端子をPICから引いてきたもので、今回のPICKitには関係ない。


2022年5月28日土曜日

Xサーバでdjango 静的ファイルについて

 Xサーバに静的ファイルを置く場合、settings.pyの中のSTATIC_URLに記述しておくといいようだ。そのうえで

HTMLテンプレートの1行目に

{% load static %}を挿入

<link rel="stylesheet" href="{% static 'アプリのdirName/css/style.css' %}>を<head>に入れておくといい


2022年5月22日日曜日

FT-891のファームウエア

  FT-891の21MHzあたりのSSBでは、なぜかSメータが振れない。検索すると、どうやらファームウエアのアップデートが必要な感じがする。でも、今使っているファームウエアのバージョンが、2021.2のものより新しい気もするのだが、、、。ものは、試しでネット上のものを適用してみた。そしたら、なぜか解決した。

2022年5月21日土曜日

django の設定 諸々

〇  settings.pyは

ALLOWED_HOSTS = ['公開用ドメイン名','localhost','127.0.0.1']

のようにしておくと、ローカルと公開用フォルダで同じファイルが使えて、便利

gitを公開用へのアップロードに用に使おうとしたが、いまいち細かい操作が心配なので、結局FTPを使うことにした。ただ、ローカルの内容は、gitで保管していくことにした。


〇urls.pyは

 上から順に照合していく

   path('admin/',admin.site.urls),

   path('',include('test.urls'),

  2行目のように何も指定しないなら、admin以外のどんな文字列も2つめに照合

〇 makemigrationsコマンドは アプリごとに

  python3 manage.py makemigrations (アプリ名)

〇 Xサーバでは、admin画面はcssが読み込めないとあるようだが

   http://liberal.triplearner.com/2021/05/09/django-xserver2/




wslでdjango その2

 wslをvscodeで使ってみる

VisualStudioCodeリモート開発拡張パックをサイトからインストール

Remote WSLのインストールを促される

左下に緑色のバックカラーのアイコンがあらわれるのでこれをクリック

*******

まだ、使い方がよくわかってないが

ターミナルは

sudo suで

conda acitivate (環境名)

が使えるようになるようだ


githubはtokenで最近、アクセス必要になった

githubサイトで、右上のメニューからsettigns>developer settigns>personal access tokenで取得できるようだ

2022年5月19日木曜日

xサーバにdjango その4

 manage.pyがあるディレクトリに.htaccessとindex.cgiを設置
仮想環境のパス確認は conda info -e 
この結果を参考に index.cgiを以下のように

#!/home/...仮想環境のパス.../python3.8
# coding: utf-8
import sys, os
import cgitb  #cgitbでトレースバックを生成する
sys.path.insert(0, '/home/....仮想環境のパス..../bin')
os.environ['DJANGO_SETTINGS_MODULE'] = 'プロジェクト名.settings'  
from wsgiref.handlers import CGIHandler
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application() 
CGIHandler().run(application)
注意!!!***先頭は最後pythonでなくpython3.8がいいようだった。
なお、全角スペースがなぜか入っていたりして、うまくいかないときあったので
サンプルからコピーしてきたとき、混じったのかも。

chmod 755 index.cgi

.htaccessは
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /ルートディレクトリに合わせる/index.cgi/$1 [QSA,L]
静的ファイルをまとめる
python manage.py collectstatic

ようやくxサーバでhttps:// ドメイン名 /adminが出るようになった。djangoが使えそう。

2022年5月17日火曜日

wslでdjango その1

 ローカルでもdjangoいれてみる
まずminicondaを入れてみる
 wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
 sh Miniconda3-latest-Linux-x86_64.sh
source .bashrc
プロンプトの色が見にくいので
dircolors -p > ~/.dircolors
34青を37白に
eval $(dircolors -b ~/.dircolors)を.bashrcに追記

condaで仮想環境に入ったら
conda install django==3.2
django-admin startproject helloworld
cd helloworld
python3 manage.py runserver
でhttp://127.0.0.1:8000/で確認できる

2022年5月16日月曜日

xサーバにdjango その3

minicondaを入れたが、勝手にbase環境に入らないように設定可(要再ログイン) 
 conda config --set auto_activate_base false
自動的にbase環境に入るように設定したい場合は
 conda config --set auto_activate_base true
conda create -n py38 python=3.8
で、pythonのバージョンを指定して環境を作成できる。
いっしょに、pipやopensslなども入れてくれるようだ。
環境の有効、無効の切り替えは
conda activate py38
conda deactivate
環境のリスト conda info -e
削除は いったん conda deactivateしてからconda remove --n py38 --all
conda install django==3.2
***Gitの準備 を参考にさせていただきました
サーバ上のホームページを設置するディレクトリ内  $ git init
$ git init --bare    作成する場所は、非公開ディレクトリに「プロジェクト名.git」という名前でディレクトリを作ってその中でこのコマンドを実行←ここが重要

「post-receive」というファイルを作って、ベアリポジトリのディレクトリ内の「hooks」というディレクトリの中に保存    ベアリポジトリにPushされたタイミングで自動的にこのファイルが実行   「post-receive」ファイルのパーミッションを「777」
#!/bin/sh
cd ~/[ドメイン名]/public_html/[プロジェクト名]
unset GIT_DIR
git pull origin master

本番リポジトリにリモートリポジトリの登録をしておきます。リモートリポジトリには、先程作ったベアリポジトリを指定します。
$ git remote add origin ~/[ドメイン名]/[プロジェクト名].git
一度登録したリモートリポジトリを変更したい場合は、以下のコマンド。
$ git remote set-url origin ~/[ドメイン名]/[プロジェクト名].git
登録内容を確認するには、以下のコマンド。
$ git remote -v
ローカルリポジトリにもリモートリポジトリとして、サーバのベアリポジトリを登録します。
#リモートリポジトリの登録(エックスサーバーの場合)
$ git remote add origin ssh://[サーバID]@[ドメイン名]:10022/home/[サーバID]/[ドメイン名]/[プロジェクト名].git

#ローカルリポジトリからリモートリポジトリへプッシュ
$ git push origin master

2022年5月15日日曜日

xサーバにdjango その2

 ということで curlの最新版を入れることに

その前にopensslも最新版にしたほうがいいらしい

$ wget http://www.openssl.org/source/openssl-1.1.1o.tar.gz
$ tar xvfz openssl-1.1.1o.tar.gz

$ cd openssl-1.1.1o

$ ./config shared --prefix=$HOME/opt/ssl --openssldir=$HOME/opt/ssl
$ make
$ make install

curlもアップデート インストール
$ wget https://curl.haxx.se/download/curl-7.80.0.tar.gz
$ tar zxvf curl-7.80.0.tar.gz
$ cd curl-7.80.0
$ ./configure --with-ssl=$HOME/opt/ssl --enable-libcurl-option -- prefix=$HOME/opt/curl
$ make
$ make install
$ export PATH=$HOME/opt/curl:$PATH
$ source .bashrc

ここで、Linuxbrewを入れようとすると、Homebrewを入れるよう促される。
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
しかし、gitが新versionになっていない。

途中libで始まるライブラリがないといわれるので
cd ~/opt/curl/lib
ln -s $HOME/opt/ssl/lib/libssl.so.1.1 libssl.so.1.1
ln -s $HOME/opt/ssl/lib/libcrypto.so.1.1 libcrypto.so.1.1

export PATH=$HOME/opt/curl/bin:$PATH
source .bashrc
ようやくHomebrewインストールにこぎつけたが、「sudo を実行できません。」で結局だめでした

minicondaをinstall

$ wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
$ sh Miniconda3-latest-Linux-x86_64.sh
source .bashrc


export PATH=/home/******/miniconda3/bin:$PATH