2015/03/28

Arduino SNMP溫度監控: 分析oid

上一篇講到了可以接受自訂oid後,
這篇要來說要怎麼分析。

格式定義

首先,我定義的格式為:
1.3.6.1.4.1.36582.X.Y
X為Arduino 的 Analog Input接頭(A2~A5),所以X範圍是2~5
Y是多工器(MUX)的接腳,範圍是0~8

X.Y的長度最多是3,所以可以抓取oid的後3字串,在用"."切割得到X跟Y。

取得後3的字串

使用函數:strncpy(結果字串 , 來源字串, 字串長度);
char oidLastTwo[4] = "";
strncpy(oidLastTwo, oid + locTempPrefix, 3);

應該要特別解釋的是 oid + locTempPrefix,來源字串為什麼加上一個整數?
因為oid是一個字串指標,值是記憶體位址,如果加上數字代表是移動字串的位置

例如(以下是為了舉例,真實不能這樣寫):
oid = "ABCDEF";  oid + 2 = "CDEF";

所以 1.3.6.1.4.1.36582.X.Y + 18("1.3.6.1.4.1.36582."的長度),
所取得的字串就是X.Y...,取三個得到 X.Y。

可以用終端機測試一下
char oidLastTwo[4] = "";
Serial.print("Last Two Segment: ");
Serial.print(oidLastTwo);
Serial.print(" oid: ");
Serial.println(oid);

切割字串

使用函數:sscanf(來源, 格式, 切割結果1 [, 切割結果2...] );

int analogPin;
int muxPin;
sscanf(oidLastTwo, "%d.%d", &analogPin, &muxPin);

切割結果會根據你的格式改變,我這邊只取得兩個%d(數字),所以也只給兩個變數;&是傳記憶體位址進去。

最後就可以得到 analogPin(X) 跟 muxPin(Y)。

可以用終端機測試一下
Serial.print("Selected AnalogPin: ");
Serial.print(analogPin);
Serial.print(" Selected muxPin: ");
Serial.println(muxPin);

整合抓取溫度程式

宣告區增加

//Thermistor
#include <math.h>
static float pad = 9900;
static float thermr = 10000; 
#define muxPINA 2
#define muxPINB 3
#define muxPINC 4
int muxA = 0;
int muxB = 0;
int muxC = 0;

Setup() 增加

pinMode(muxPINA, OUTPUT);
pinMode(muxPINB, OUTPUT);
pinMode(muxPINC, OUTPUT);

複製 Thermistor 函式到喜歡的地方 


為了方便呼叫,我另外寫了一個函數來抓溫度;大部分的Code都跟之前的範例一樣。
int32_t fetchTemp(int analogPin, int muxCount){
 float temp = 0;

 if( analogPin<2 data-blogger-escaped-analogpin="">5 || muxCount > 7 ){
  // analogPin 0, 1 used for ethernet shield SD Card Control
  // Multiplexer only 0~7
  return temp;
 }

 //get temp from Thermistor
 muxA = bitRead(muxCount,0);
 muxB = bitRead(muxCount,1);
 muxC = bitRead(muxCount,2);

 //select mux pint
 digitalWrite(muxPINA, muxA);
 digitalWrite(muxPINB, muxB);
 digitalWrite(muxPINC, muxC);

 temp = Thermistor(analogRead(analogPin));

 if(true ){
  unsigned long time = millis();
  Serial.print(time);  
  Serial.print(": analogPin ");
  Serial.print(analogPin);
  Serial.print(" MUX Port");
  Serial.print(muxCount);
  Serial.print("=> ");
  Serial.print("Celsius: "); 
  Serial.print(temp,2);               
  Serial.println("");
  Serial.println("");
 }

 return (int) (temp*100.0);
}

第一個if用來檢查輸入的值是否正確analogPin(2~5), muxPin(0~7)
第二個if用來輸出除錯訊息,true改false就不會印出來了

比較要注意的是最後一行回傳了 temp*100.0
由於SNMP協定沒有"浮點數"的型態,只能傳送整數;

所以這邊*100後轉成整數(int)取得小數點後第二位,到了 Cacti 再轉回來。

最後把
temp = fetchTemp(analogPin, muxPin);
加到 pduReceived() 判斷式內即可。


結果畫面




[Source Code]
https://github.com/Aspertw/ArduinoSNMPTemp/blob/master/SnmpThermal.ino

2 則留言:

  1. 想請教,如何將收到的字串切割成我要的格式列如:abcd,ok,0101,0101 我只要0101,0101這樣如何處理,字串的格式會變化

    回覆刪除
  2. 要視您的字串格式怎麼變化? 因為程式只能寫死的
    所以要分析出固定的格式。如果是四串字用逗號分開,
    那可以直接用sscanf(source, "%c, %c, %c, %c, ...)
    或是用str split的關鍵字去搜尋做法
    http://stackoverflow.com/questions/9210528/split-string-with-delimiters-in-c

    [sscanf]
    http://ccckmit.wikidot.com/cp:sscanf

    回覆刪除