initial
This commit is contained in:
parent
c6c160ba87
commit
565742c1be
8 changed files with 24 additions and 296 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -3,3 +3,4 @@
|
||||||
/bin/
|
/bin/
|
||||||
/curses/
|
/curses/
|
||||||
/info/
|
/info/
|
||||||
|
temp_sensor
|
Binary file not shown.
Before Width: | Height: | Size: 825 KiB |
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 1 MiB |
114
monitor.cpp
114
monitor.cpp
|
@ -1,114 +0,0 @@
|
||||||
#include <iostream>
|
|
||||||
#include <cassert>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <sstream>
|
|
||||||
#include <cctype>
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
const string WHITESPACE = " \n\r\t\f\v";
|
|
||||||
string ltrim(const string& s) {
|
|
||||||
size_t start = s.find_first_not_of(WHITESPACE);
|
|
||||||
return (start == string::npos) ? "" : s.substr(start);
|
|
||||||
}
|
|
||||||
string rtrim(const string& s) {
|
|
||||||
size_t end = s.find_last_not_of(WHITESPACE);
|
|
||||||
return (end == string::npos) ? "" : s.substr(0, end + 1);
|
|
||||||
}
|
|
||||||
string trim(const string& s) { return rtrim(ltrim(s)); }
|
|
||||||
|
|
||||||
void split_comma(string &s, vector<string> &l);
|
|
||||||
void sort_names(vector<string> &l, vector<int> &order, int &num);
|
|
||||||
int max_len(vector<string> &l);
|
|
||||||
|
|
||||||
int main(int argc,char *argv[]) {
|
|
||||||
string name_line, value_line;
|
|
||||||
getline(cin, name_line);
|
|
||||||
// cout<<name_line<<endl;
|
|
||||||
|
|
||||||
int num; int name_length_max;
|
|
||||||
vector<int> orders;
|
|
||||||
vector<string> names, values;
|
|
||||||
vector<double> raw_values;
|
|
||||||
|
|
||||||
split_comma(name_line, names);
|
|
||||||
num = names.size();
|
|
||||||
sort_names(names, orders, num);
|
|
||||||
name_length_max = max_len(names);
|
|
||||||
|
|
||||||
for(int i=0;i<num;++i) {
|
|
||||||
int space_num = name_length_max + 2 - names[orders[i]].size();
|
|
||||||
cout<<names[orders[i]];
|
|
||||||
for(int j=0;j<space_num;++j) cout<<" ";
|
|
||||||
cout<<"| "<<endl;
|
|
||||||
}
|
|
||||||
// cout<<num<<endl;
|
|
||||||
// for(int i=0;i<num;++i) cout<<" "<<endl;
|
|
||||||
cout<<"\x1b[100D"<<"\x1b["<<num<<"A"<<flush;
|
|
||||||
// ANSI Escape sequences http://ascii-table.com/ansi-escape-sequences.php
|
|
||||||
// https://www.lihaoyi.com/post/BuildyourownCommandLinewithANSIescapecodes.html#progress-indicator
|
|
||||||
|
|
||||||
while(getline(cin, value_line)) {
|
|
||||||
// cout<<"\x1b[1000D"<<value_line<<flush;
|
|
||||||
split_comma(value_line, values);
|
|
||||||
assert(values.size() == num);
|
|
||||||
|
|
||||||
for(int i=0;i<names.size();++i) {
|
|
||||||
cout<<"\x1b["<<name_length_max + 4<<"C"<<flush;
|
|
||||||
cout<<values[orders[i]]<<endl;
|
|
||||||
}
|
|
||||||
// cout<<num<<"=="<<endl;
|
|
||||||
cout<<"\x1b[100D"<<"\x1b["<<num<<"A"<<flush;
|
|
||||||
usleep(500000); // sleep(1); https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/usleep.3.html
|
|
||||||
}
|
|
||||||
cout<<endl;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void split_comma(string &s, vector<string> &l) {
|
|
||||||
l.clear();
|
|
||||||
stringstream s_stream(s);
|
|
||||||
while(s_stream.good()) {
|
|
||||||
string w;
|
|
||||||
getline(s_stream, w, ','); //get first string delimited by comma
|
|
||||||
w=trim(w);
|
|
||||||
if(!w.empty())
|
|
||||||
l.push_back(w);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void sort_names(vector<string> &l, vector<int> &order, int &num) {
|
|
||||||
vector< pair<string, int> > l_id;
|
|
||||||
for(int i=0;i<num;++i) l_id.push_back(make_pair(l[i], i));
|
|
||||||
sort(l_id.begin(), l_id.end());
|
|
||||||
|
|
||||||
order.clear();
|
|
||||||
for(int i=0;i<num;++i) order.push_back(l_id[i].second);
|
|
||||||
}
|
|
||||||
|
|
||||||
int max_len(vector<string> &l) {
|
|
||||||
int res = 0;
|
|
||||||
for(int i=0;i<l.size();++i)
|
|
||||||
if(l[i].size() > res)
|
|
||||||
res = l[i].size();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
cout << "\r%1"<<flush;
|
|
||||||
sleep(1);
|
|
||||||
cout << "\r%2"<<flush;
|
|
||||||
sleep(1);
|
|
||||||
cout << "\r%3"<<flush;
|
|
||||||
cout << endl;
|
|
||||||
*/
|
|
132
monitor.py
132
monitor.py
|
@ -1,132 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
import curses
|
|
||||||
import sys, os
|
|
||||||
import time
|
|
||||||
|
|
||||||
import platform
|
|
||||||
# import os, platform, subprocess
|
|
||||||
def get_processor_name():
|
|
||||||
return "Apple M1"
|
|
||||||
if platform.system() == "Darwin":
|
|
||||||
# os.environ['PATH'] = os.environ['PATH'] + os.pathsep + '/usr/sbin'
|
|
||||||
command ="/usr/sbin/sysctl -n machdep.cpu.brand_string"
|
|
||||||
return subprocess.check_output(command).strip()
|
|
||||||
return ""
|
|
||||||
|
|
||||||
def get_OS_ver():
|
|
||||||
ver = platform.mac_ver();
|
|
||||||
return f'macOS {ver[0]} ({ver[2]})'
|
|
||||||
|
|
||||||
log_flag = False;
|
|
||||||
if log_flag:
|
|
||||||
log_file = open("message.log","w")
|
|
||||||
|
|
||||||
def get_sorted_names():
|
|
||||||
# get `name1, name2, name3,` as names_str
|
|
||||||
names_str = sys.stdin.readline().strip()
|
|
||||||
names = names_str.split(',')[:-1] # ignore last '' item
|
|
||||||
names = [name.strip() for name in names]
|
|
||||||
name_i = [(name, i) for i, name in enumerate(names)]
|
|
||||||
|
|
||||||
# alphabetical order
|
|
||||||
sorted_name_i = sorted(name_i, key=lambda x: x[0].lower())
|
|
||||||
sorted_names = [name for name, i in sorted_name_i]
|
|
||||||
sorted_names = [name.replace('Sensor','#') for name in sorted_names]
|
|
||||||
|
|
||||||
ordered_list = [i for name, i in sorted_name_i]
|
|
||||||
# i-th place holds nums[ordered_list[i]]
|
|
||||||
|
|
||||||
if log_flag:
|
|
||||||
print(names_str, '\n', sep='\n', file=log_file, flush=True) # sorted_name_i
|
|
||||||
return sorted_names, ordered_list
|
|
||||||
|
|
||||||
def get_sorted_nums(ordered_list):
|
|
||||||
nums_str = sys.stdin.readline().strip()
|
|
||||||
nums = nums_str.split(',')[:-1]
|
|
||||||
nums = [num.strip() for num in nums]
|
|
||||||
assert len(nums) == len(ordered_list)
|
|
||||||
|
|
||||||
sorted_nums = [float(nums[ordered_list[i]]) for i in range(len(nums))]
|
|
||||||
if log_flag:
|
|
||||||
print(nums_str, '\n', sep='\n', file=log_file, flush=True) # sorted_nums
|
|
||||||
return sorted_nums
|
|
||||||
|
|
||||||
def main(stdscr):
|
|
||||||
curses.start_color()
|
|
||||||
curses.use_default_colors()
|
|
||||||
# 57 items, max name len = 25
|
|
||||||
# sorted_names = ['ANE MTR Temp Sensor1', 'GPU MTR Temp Sensor1', 'GPU MTR Temp Sensor4', 'ISP MTR Temp Sensor5', 'NAND CH0 temp', 'PMGR SOC Die Temp Sensor0', 'PMGR SOC Die Temp Sensor1', 'PMGR SOC Die Temp Sensor2', 'PMU TP3w', 'PMU tcal', 'PMU tdev1', 'PMU tdev2', 'PMU tdev3', 'PMU tdev4', 'PMU tdev5', 'PMU tdev6', 'PMU tdev7', 'PMU tdev8', 'PMU tdie1', 'PMU tdie2', 'PMU tdie4', 'PMU tdie5', 'PMU tdie6', 'PMU tdie7', 'PMU tdie8', 'PMU2 TR0Z', 'PMU2 TR1d', 'PMU2 TR1l', 'PMU2 TR2d', 'PMU2 TR2l', 'PMU2 TR3b', 'PMU2 TR3d', 'PMU2 TR4b', 'PMU2 TR4d', 'PMU2 TR5b', 'PMU2 TR5d', 'PMU2 TR6b', 'PMU2 TR7b', 'PMU2 TR8b', 'SOC MTR Temp Sensor0', 'SOC MTR Temp Sensor1', 'SOC MTR Temp Sensor2', 'eACC MTR Temp Sensor0', 'eACC MTR Temp Sensor3', 'gas gauge battery', 'gas gauge battery', 'gas gauge battery', 'gas gauge battery', 'gas gauge battery', 'gas gauge battery', 'pACC MTR Temp Sensor2', 'pACC MTR Temp Sensor3', 'pACC MTR Temp Sensor4', 'pACC MTR Temp Sensor5', 'pACC MTR Temp Sensor7', 'pACC MTR Temp Sensor8', 'pACC MTR Temp Sensor9'];
|
|
||||||
|
|
||||||
sorted_names, ordered_list = get_sorted_names()
|
|
||||||
n = len(sorted_names)
|
|
||||||
max_name_length = max(map(len, sorted_names));
|
|
||||||
|
|
||||||
ncol = 2
|
|
||||||
nrow0 = 3
|
|
||||||
nrow1 = n//2 + 1
|
|
||||||
|
|
||||||
sys_info = f'{get_processor_name()}, {get_OS_ver()}' # Processor: , OS:
|
|
||||||
|
|
||||||
max_nums = None
|
|
||||||
|
|
||||||
while True:
|
|
||||||
# Clear screen
|
|
||||||
stdscr.clear()
|
|
||||||
ny,nx = stdscr.getmaxyx()
|
|
||||||
# Coordinates are always passed in the order y,x
|
|
||||||
# the top-left corner of a window is coordinate (0,0).
|
|
||||||
# assert nx>=80 and ny>=34
|
|
||||||
if not (nx>=80 and ny>=34):
|
|
||||||
stdscr.addnstr(0,0, 'enlarge the size of this terminal...', 50, curses.A_REVERSE)
|
|
||||||
stdscr.addnstr(1,0, f'requires min 32x80, now {ny}x{nx} (row x col)', 50)
|
|
||||||
stdscr.refresh()
|
|
||||||
time.sleep(0.2)
|
|
||||||
continue
|
|
||||||
|
|
||||||
stdscr.box()
|
|
||||||
stdscr.addnstr(0,5, f' {sys_info}, {n} sensors ', 80) # (max_name_length={max_name_length})
|
|
||||||
stdscr.addnstr(ny-1,5, f' Press Ctrl+C to exit ', 80)
|
|
||||||
|
|
||||||
xmid = nx//2 # //ncol
|
|
||||||
# __|__
|
|
||||||
# xmid
|
|
||||||
# xmid+3
|
|
||||||
|
|
||||||
sorted_nums = get_sorted_nums(ordered_list)
|
|
||||||
if max_nums is not None:
|
|
||||||
max_nums = [max(x,y) for x,y in zip(sorted_nums, max_nums)]
|
|
||||||
else:
|
|
||||||
max_nums = sorted_nums
|
|
||||||
|
|
||||||
# for y in range(-1, nrow1):
|
|
||||||
# stdscr.addnstr(nrow0+y,xmid, '|', 1)
|
|
||||||
stdscr.vline(nrow0-1, xmid, curses.ACS_VLINE, nrow1+1)
|
|
||||||
|
|
||||||
curses.init_pair(1, 14, -1)
|
|
||||||
titles = ['Sensor Name','now /max˚C']
|
|
||||||
stdscr.addnstr(nrow0-1, 2, f'{titles[0]:{max_name_length+3}} {titles[1]}', 37, curses.color_pair(1))
|
|
||||||
stdscr.addnstr(nrow0-1,xmid+3, f'{titles[0]:{max_name_length+3}} {titles[1]}', 37, curses.color_pair(1))
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
for y in range(0, nrow1):
|
|
||||||
if i<n:
|
|
||||||
stdscr.addnstr(nrow0+y, 2, f'{sorted_names[i]:{max_name_length+2}} {sorted_nums[i]:5.1f} /{max_nums[i]:5.1f}', 37)
|
|
||||||
i += 1
|
|
||||||
for y in range(0, nrow1):
|
|
||||||
if i<n:
|
|
||||||
stdscr.addnstr(nrow0+y,xmid+3, f'{sorted_names[i]:{max_name_length+2}} {sorted_nums[i]:5.1f} /{max_nums[i]:5.1f}', 37)
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
stdscr.refresh()
|
|
||||||
# stdscr.getkey()
|
|
||||||
time.sleep(0.4)
|
|
||||||
|
|
||||||
# https://stackoverflow.com/questions/21120947/catching-keyboardinterrupt-in-python-during-program-shutdown/21144662
|
|
||||||
try:
|
|
||||||
curses.wrapper(main)
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
# print('Finish Monitoring Temperature!')
|
|
||||||
try:
|
|
||||||
sys.exit(0)
|
|
||||||
except SystemExit:
|
|
||||||
os._exit(0)
|
|
45
readme.md
45
readme.md
|
@ -1,45 +0,0 @@
|
||||||
# Temperature Sensor Monitor for Apple Silicon M1
|
|
||||||
|
|
||||||
- `temp_sensor.m`: modified on the Objective-C [code](https://github.com/freedomtan/sensors/blob/master/sensors/sensors.m) for iOS sensor by [freedomtan](https://github.com/freedomtan);
|
|
||||||
|
|
||||||
- `monitor.py`: a wrapper for `temp_sensor.m` output for monitoring temperature in the terminal.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
Compile `temp_sensor.m` (by `clang -Wall -v temp_sensor.m -framework IOKit -framework Foundation -o temp_sensor`, Xcode on M1 mac needed). Then
|
|
||||||
|
|
||||||
`./temp_sensor | ./monitor.py` or `./temp_sensor`
|
|
||||||
|
|
||||||
Only test with my Macbook air with M1. Please check your mac's `ioreg -lfx` output to make changes in `temp_sensor.m` if needed.
|
|
||||||
|
|
||||||
## References
|
|
||||||
|
|
||||||
For **better names** (e.g. what is `PMU TP3w` ?) for the sensors, please refer to
|
|
||||||
|
|
||||||
https://github.com/exelban/stats/blob/master/Modules/Sensors/values.swift
|
|
||||||
|
|
||||||
https://github.com/acidanthera/VirtualSMC/blob/master/Docs/SMCSensorKeys.txt
|
|
||||||
|
|
||||||
Here is a similar code in swift for getting sensor values using IOKit (for intel Mac)
|
|
||||||
|
|
||||||
https://github.com/exelban/stats/blob/master/Modules/Sensors/values.swift
|
|
||||||
|
|
||||||
For intel Mac, an easier way to get sensor infomation:
|
|
||||||
|
|
||||||
`sudo powermetrics`
|
|
||||||
|
|
||||||
|
|
||||||
## Demo: screen shot and screen record
|
|
||||||
- screen record : screen_record.mp4[1.4MB] or
|
|
||||||
![screen record](https://raw.githubusercontent.com/fermion-star/apple_sensors/master/demo/screen_record.low.gif)
|
|
||||||
|
|
||||||
- screen shot
|
|
||||||
![screen shot](https://raw.githubusercontent.com/fermion-star/apple_sensors/master/demo/screen_shot.png)
|
|
||||||
<!---
|
|
||||||
![screen record](screen_record.mp4)
|
|
||||||
|
|
||||||
![screen shot](screen_shot.png)
|
|
||||||
--->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -145,16 +145,34 @@ CFArrayRef getThermalValues(CFDictionaryRef sensors) {
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double getTempValue(CFArrayRef values, int index) {
|
||||||
|
CFNumberRef value = CFArrayGetValueAtIndex(values, index);
|
||||||
|
double temp = 0.0;
|
||||||
|
CFNumberGetValue(value, kCFNumberDoubleType, &temp);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printCPUGPUTemps(CFArrayRef values) {
|
||||||
|
printf("CPU %0.1lf GPU %0.1lf, ", getTempValue(values,0), getTempValue(values,2));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void dumpValues(CFArrayRef values)
|
void dumpValues(CFArrayRef values)
|
||||||
{
|
{
|
||||||
long count = CFArrayGetCount(values);
|
long count = CFArrayGetCount(values);
|
||||||
|
|
||||||
|
double accumTemp = 0.0;
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
CFNumberRef value = CFArrayGetValueAtIndex(values, i);
|
CFNumberRef value = CFArrayGetValueAtIndex(values, i);
|
||||||
double temp = 0.0;
|
double temp = 0.0;
|
||||||
CFNumberGetValue(value, kCFNumberDoubleType, &temp);
|
CFNumberGetValue(value, kCFNumberDoubleType, &temp);
|
||||||
// NSLog(@"value = %lf\n", temp);
|
// NSLog(@"value = %lf\n", temp);
|
||||||
printf("%0.1lf, ", temp);
|
//printf("%0.1lf, ", temp);
|
||||||
|
if(temp > 0)
|
||||||
|
accumTemp+=temp;
|
||||||
}
|
}
|
||||||
|
printf("%0.0lf", accumTemp/count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dumpNames(CFArrayRef names, char *cat)
|
void dumpNames(CFArrayRef names, char *cat)
|
||||||
|
@ -230,10 +248,10 @@ int main () {
|
||||||
// printf("freq, v_bat, a_bat, temp_bat");
|
// printf("freq, v_bat, a_bat, temp_bat");
|
||||||
// dumpNames(voltageNames, "V");
|
// dumpNames(voltageNames, "V");
|
||||||
// dumpNames(currentNames, "A");
|
// dumpNames(currentNames, "A");
|
||||||
dumpNames(thermalNames, "C");
|
//dumpNames(thermalNames, "C");
|
||||||
printf("\n"); fflush(stdout);
|
//printf("\n"); fflush(stdout);
|
||||||
|
|
||||||
while (1) {
|
//while (1) {
|
||||||
CFArrayRef currentValues = getPowerValues(currentSensors);
|
CFArrayRef currentValues = getPowerValues(currentSensors);
|
||||||
CFArrayRef voltageValues = getPowerValues(voltageSensors);
|
CFArrayRef voltageValues = getPowerValues(voltageSensors);
|
||||||
CFArrayRef thermalValues = getThermalValues(thermalSensors);
|
CFArrayRef thermalValues = getThermalValues(thermalSensors);
|
||||||
|
@ -248,7 +266,7 @@ int main () {
|
||||||
CFRelease(currentValues);
|
CFRelease(currentValues);
|
||||||
CFRelease(voltageValues);
|
CFRelease(voltageValues);
|
||||||
CFRelease(thermalValues);
|
CFRelease(thermalValues);
|
||||||
}
|
//}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
NSLog(@"%@\n", CFArrayGetValueAtIndex(currentNames, 0));
|
NSLog(@"%@\n", CFArrayGetValueAtIndex(currentNames, 0));
|
||||||
|
|
Loading…
Reference in a new issue