![見出し画像](https://assets.st-note.com/production/uploads/images/124958990/rectangle_large_type_2_e610320bc5b348261d4b795cdd02a417.png?width=1200)
「実践SNMP教科書」復刻のために気象情報を取得するプログラムを作った
今朝は4時に起きました。新人助手の猫さんは、後から起きてきました。
さて、「実践SNMP教科書」の復刻をしていますが、大きな問題に直面しました。拡張MIBモジュールの対象となっている気象観測装置を捨ててしまったことです。
![](https://assets.st-note.com/img/1702935046159-CBTSGohvjC.png?width=1200)
代わりに、
を使うことにしました。
の記事でも使ったものです。
とりあえず、取得するためのテストプログラムを作ってみました。
APIキーと位置をパラメータで指定っして気象情報を取得します。
package main
import (
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
)
type OpenWeather struct {
Coord struct {
Lon float64 `json:"lon"`
Lat float64 `json:"lat"`
} `json:"coord"`
Weather []struct {
ID int `json:"id"`
Main string `json:"main"`
Description string `json:"description"`
Icon string `json:"icon"`
} `json:"weather"`
Base string `json:"base"`
Main struct {
Temp float64 `json:"temp"`
FeelsLike float64 `json:"feels_like"`
TempMin float64 `json:"temp_min"`
TempMax float64 `json:"temp_max"`
Pressure int `json:"pressure"`
Humidity int `json:"humidity"`
SeaLevel int `json:"sea_level"`
GrndLevel int `json:"grnd_level"`
} `json:"main"`
Visibility int `json:"visibility"`
Wind struct {
Speed float64 `json:"speed"`
Deg int `json:"deg"`
Gust float64 `json:"gust"`
} `json:"wind"`
Clouds struct {
All int `json:"all"`
} `json:"clouds"`
Dt int `json:"dt"`
Sys struct {
Type int `json:"type"`
ID int `json:"id"`
Country string `json:"country"`
Sunrise int `json:"sunrise"`
Sunset int `json:"sunset"`
} `json:"sys"`
Timezone int `json:"timezone"`
ID int `json:"id"`
Name string `json:"name"`
Cod int `json:"cod"`
}
func main() {
if len(os.Args) < 3 {
log.Fatalf("openweather <apkey> <loc>")
}
url := "https://api.openweathermap.org/data/2.5/weather?q=" + os.Args[2] + "&units=metric&APPID=" + os.Args[1]
r, err := http.Get(url)
if err != nil {
log.Fatalln(err)
}
defer r.Body.Close()
b, err := io.ReadAll(r.Body)
if err != nil {
log.Fatalln(err)
}
data := new(OpenWeather)
if err := json.Unmarshal(b, data); err != nil {
log.Fatalln(err)
}
fmt.Printf("%d %d %d %d %d %d\n", data.Dt, int64(data.Main.Temp*10), data.Main.Humidity, data.Main.Pressure, data.Wind.Deg, int64(data.Wind.Speed))
}
OpenWeatherのデータ型は、サーバーの応答のJSONから
を使って作りました。
{"coord":{"lon":139.5577,"lat":35.8578},"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04n"}],"base":"stations","main":{"temp":5.37,"feels_like":2.04,"temp_min":3.68,"temp_max":7.75,"pressure":1022,"humidity":47,"sea_level":1022,"grnd_level":1021},"visibility":10000,"wind":{"speed":4.5,"deg":339,"gust":7.69},"clouds":{"all":55},"dt":1702843951,"sys":{"type":2,"id":2001249,"country":"JP","sunrise":1702849566,"sunset":1702884595},"timezone":32400,"id":6940394,"name":"Fujimi","cod":200}
を入れれば、
type AutoGenerated struct {
Coord struct {
Lon float64 `json:"lon"`
Lat float64 `json:"lat"`
} `json:"coord"`
Weather []struct {
ID int `json:"id"`
Main string `json:"main"`
Description string `json:"description"`
Icon string `json:"icon"`
} `json:"weather"`
Base string `json:"base"`
Main struct {
Temp float64 `json:"temp"`
FeelsLike float64 `json:"feels_like"`
TempMin float64 `json:"temp_min"`
TempMax float64 `json:"temp_max"`
Pressure int `json:"pressure"`
Humidity int `json:"humidity"`
SeaLevel int `json:"sea_level"`
GrndLevel int `json:"grnd_level"`
} `json:"main"`
Visibility int `json:"visibility"`
Wind struct {
Speed float64 `json:"speed"`
Deg int `json:"deg"`
Gust float64 `json:"gust"`
} `json:"wind"`
Clouds struct {
All int `json:"all"`
} `json:"clouds"`
Dt int `json:"dt"`
Sys struct {
Type int `json:"type"`
ID int `json:"id"`
Country string `json:"country"`
Sunrise int `json:"sunrise"`
Sunset int `json:"sunset"`
} `json:"sys"`
Timezone int `json:"timezone"`
ID int `json:"id"`
Name string `json:"name"`
Cod int `json:"cod"`
}
を作ってくれます。かなり便利です。
![](https://assets.st-note.com/img/1702935918809-ezXkKqxgjo.png?width=1200)
うまく行ったので、データ取得を定期的に実行するプログラムにしてみました。
package main
import (
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
"strings"
"time"
)
type OpenWeather struct {
Coord struct {
Lon float64 `json:"lon"`
Lat float64 `json:"lat"`
} `json:"coord"`
Weather []struct {
ID int `json:"id"`
Main string `json:"main"`
Description string `json:"description"`
Icon string `json:"icon"`
} `json:"weather"`
Base string `json:"base"`
Main struct {
Temp float64 `json:"temp"`
FeelsLike float64 `json:"feels_like"`
TempMin float64 `json:"temp_min"`
TempMax float64 `json:"temp_max"`
Pressure int `json:"pressure"`
Humidity int `json:"humidity"`
SeaLevel int `json:"sea_level"`
GrndLevel int `json:"grnd_level"`
} `json:"main"`
Visibility int `json:"visibility"`
Wind struct {
Speed float64 `json:"speed"`
Deg int `json:"deg"`
Gust float64 `json:"gust"`
} `json:"wind"`
Clouds struct {
All int `json:"all"`
} `json:"clouds"`
Dt int `json:"dt"`
Sys struct {
Type int `json:"type"`
ID int `json:"id"`
Country string `json:"country"`
Sunrise int `json:"sunrise"`
Sunset int `json:"sunset"`
} `json:"sys"`
Timezone int `json:"timezone"`
ID int `json:"id"`
Name string `json:"name"`
Cod int `json:"cod"`
}
func main() {
if len(os.Args) < 3 {
log.Fatalf("openweather <apkey> <loc>")
}
url := "https://api.openweathermap.org/data/2.5/weather?q=" + os.Args[2] + "&units=metric&APPID=" + os.Args[1]
lastDt := 0
hist := []*OpenWeather{}
for {
data, err := getData(url)
if err != nil {
log.Println(err)
time.Sleep(time.Minute)
continue
}
if data.Dt != lastDt {
lastDt = data.Dt
o := []string{}
o = append(o, fmt.Sprintf("0 %d %d %d %d %d %d", data.Dt, int64(data.Main.Temp*10), data.Main.Humidity, data.Main.Pressure, data.Wind.Deg, int64(data.Wind.Speed)))
if len(hist) > 256 {
hist = hist[1:]
}
hist = append(hist, data)
for i, l := range hist {
o = append(o, fmt.Sprintf("%d %d %d %d %d %d %d", i+1, l.Dt, int64(l.Main.Temp*10), l.Main.Humidity, l.Main.Pressure, l.Wind.Deg, int64(l.Wind.Speed)))
}
os.WriteFile("/tmp/owd.txt", []byte(strings.Join(o, "\n")+"\n"), 0666)
}
time.Sleep(time.Minute * 1)
}
}
func getData(url string) (*OpenWeather, error) {
r, err := http.Get(url)
if err != nil {
return nil, err
}
defer r.Body.Close()
b, err := io.ReadAll(r.Body)
if err != nil {
return nil, err
}
data := new(OpenWeather)
if err := json.Unmarshal(b, data); err != nil {
return nil, err
}
return data, nil
}
ちゃんと取得できているようです。
# cat /tmp/owd.txt
0 1702935005 43 58 1026 360 2
1 1702930175 39 57 1026 354 3
2 1702930835 39 57 1026 354 3
3 1702931437 40 57 1026 352 3
4 1702932038 40 57 1026 352 3
5 1702932821 42 58 1026 352 3
6 1702933181 43 57 1026 352 3
7 1702933805 42 58 1026 352 3
8 1702934625 42 58 1026 352 3
9 1702935005 43 58 1026 360 2
外は4.2℃です。寒い
今朝は時間切れです。明日、このデータを読み込んで値を返す拡張MIBのエージェントを作ろうと思います。
ここから先は
0字
![](https://assets.st-note.com/production/uploads/images/14333815/profile_ee1accba5615957e5029db85d57fdb0a.jpg?fit=bounds&format=jpeg&quality=85&width=330)
SNMPの仕様について解説した本やサイトは、沢山あると思います。
独自の拡張MIBを自分で設計してMIBファイルやエージェントを作る方法を解説した教科書はないと思います。
実践SNMP教科書 復刻版
500円
20年近く前に書いた「実践SNMP教科書」を現在でも通用する部分だけ書き直して復刻するマガジンです。最近MIBの設計で困っている人に遭遇し…
開発のための諸経費(機材、Appleの開発者、サーバー運用)に利用します。 ソフトウェアのマニュアルをnoteの記事で提供しています。 サポートによりnoteの運営にも貢献できるのでよろしくお願います。