Skip to content
This repository has been archived by the owner on Sep 8, 2024. It is now read-only.

Commit

Permalink
- Status shows fan speeds
Browse files Browse the repository at this point in the history
- Changed default update intervals
- Fans update intervals can be set individually
- All Dell fans are enabled/disabled together
- AUR package name changed

Signed-off-by: Hayden Briese <[email protected]>
  • Loading branch information
hbriese committed Aug 5, 2020
1 parent 0517d18 commit 4673ce5
Show file tree
Hide file tree
Showing 18 changed files with 380 additions and 251 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ sudo yum –nogpgcheck install ./fancon*.rpm

##### Arch Linux (AUR)
```bash
git clone https://aur.archlinux.org/fancon-git.git; cd fancon-git
git clone https://aur.archlinux.org/fancon.git; cd fancon
makepkg -sirc
```

Expand All @@ -55,20 +55,20 @@ devices {
label: "hwmon3/fan1" # Name of device - anything you want
sensor: "CPU Package" # Sensor to read - specify by label
temp_to_rpm: "39: 0%, 40: 1%, 75: 50%, 90: 100%"
# temp (optional f or F): RPM (optional % or PWM)
# temp (optional: f | F; default °C): RPM (optional: % | PWM; default RPM)
# 40: 0% Stopped at or below 40°C (°C is used if F is omitted)
# 50: 1% Lowest running speed at 50°C
# 75: 50% 50% of max RPM at 75°C, could also be written as 75: 180PWM in this case
# 194f: 100% Full speed at 90°C (194f = 90°C)
# 194f: 100% Full speed at 194°F (194f = 90°C)
rpm_to_pwm: "0: 0, 3206: 128, 4954: 180, 7281: 255" # Mappings of RPM to PWM
start_pwm: 128 # PWM at which the fan starts
interval: 500 # Milliseconds taken for the fan to reach a new speed,
# increasing improves testing accuracy but increases testing time
# interval: 500 # Fan-specific update time; increasing improves test accuracy
ignore: false # Don't control or test device; may be excluded if false
# Following only applicable to SYS & DELL devices
driver_flag: 2 # Driver flag to enable manual control
pwm_path: "/sys/class/hwmon/hwmon3/pwm1" # Path to read/write PWM
rpm_path: "/sys/class/hwmon/hwmon3/fan1_input" # Path to read RPM
# Following only applicable to SYS devices
enable_path: "/sys/class/hwmon/hwmon3/pwm1_enable" # Path to enable PWM control
}
fan {
Expand Down
2 changes: 1 addition & 1 deletion debian/changelog
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
fancon (0.22.0) UNRELEASED; urgency=low
fancon (0.23.0) UNRELEASED; urgency=low

* Initial release. Closes: #00000

Expand Down
16 changes: 10 additions & 6 deletions proto/DevicesSpec.proto
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ message Fan {
bool ignore = 8;

// SYS & DELL
string pwm_path = 10;
string rpm_path = 11;
int32 driver_flag = 10;
string pwm_path = 11;
string rpm_path = 12;

// SYS
string enable_path = 12;
int32 driver_flag = 13;
string enable_path = 13;

// NV
uint32 id = 20;
Expand Down Expand Up @@ -82,7 +82,10 @@ message FanStatus {
DISABLED = 1;
TESTING = 2;
}
Status status = 1;
string label = 1;
Status status = 2;
uint32 rpm = 3;
uint32 pwm = 4;
}

message Empty {}
Expand All @@ -96,7 +99,8 @@ service DService {
rpc GetControllerConfig(Empty) returns (ControllerConfig) {}
rpc SetControllerConfig(ControllerConfig) returns (Empty) {}

rpc Status(FanLabel) returns (FanStatus) {}
rpc GetFanStatus(FanLabel) returns (FanStatus) {}
rpc SubscribeFanStatus(Empty) returns (stream FanStatus) {}
rpc Enable(FanLabel) returns (Empty) {}
rpc EnableAll(Empty) returns (Empty) {}
rpc Disable(FanLabel) returns (Empty) {}
Expand Down
35 changes: 22 additions & 13 deletions src/Client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,14 @@ void fc::Client::run(Args &args) {
void fc::Client::stop_service() {
ClientContext context;
if (check(client->StopService(&context, empty, &empty)))
LOG(llvl::info) << "Stopped service";
LOG(llvl::info) << "Service stopped";
else
LOG(llvl::error) << "Failed to stop service";
}

optional<fc_pb::Devices> fc::Client::get_devices() {
ClientContext context;
fc_pb::Devices devices;

if (!check(client->GetDevices(&context, empty, &devices)))
return nullopt;

Expand All @@ -81,7 +80,6 @@ optional<fc_pb::Devices> fc::Client::get_devices() {
optional<fc_pb::Devices> fc::Client::get_enumerated_devices() {
ClientContext context;
fc_pb::Devices devices;

if (!check(client->GetEnumeratedDevices(&context, empty, &devices)))
return nullopt;

Expand All @@ -95,21 +93,34 @@ void fc::Client::status() {
return;
}

// Find the status of all devices
size_t longest_label = 0;
vector<fc_pb::FanStatus> statuses;
for (const auto &f : devices->fan()) {
ClientContext context;
fc_pb::FanLabel req = from(f.label());

fc_pb::FanStatus status;
if (check(client->Status(&context, req, &status)))
LOG(llvl::info) << f.label() << ": " << status_text(status.status());
if (check(client->GetFanStatus(&context, from(f.label()), &status))) {
if (const auto l = status.label().length(); l > longest_label)
longest_label = l;
statuses.push_back(move(status));
}
}

// Write out all the collected status, width adjusting the outputs
for (const auto &s : statuses) {
stringstream extras;
if (s.status() != FanStatus::FanStatus_Status_DISABLED)
extras << " " << setw(5) << s.rpm() << "rpm " << setw(3) << s.pwm()
<< "pwm";

cout << setw(longest_label) << s.label() << ": " << setw(8)
<< status_text(s.status()) << extras.rdbuf() << endl;
}
}

void fc::Client::enable(const string &flabel) {
ClientContext context;
fc_pb::FanLabel req = from(flabel);

if (check(client->Enable(&context, req, &empty)))
if (check(client->Enable(&context, from(flabel), &empty)))
LOG(llvl::info) << flabel << ": enabled";
}

Expand All @@ -121,9 +132,7 @@ void fc::Client::enable() {

void fc::Client::disable(const string &flabel) {
ClientContext context;
fc_pb::FanLabel req = from(flabel);

if (check(client->Disable(&context, req, &empty)))
if (check(client->Disable(&context, from(flabel), &empty)))
LOG(llvl::info) << flabel << ": disabled";
}

Expand Down
3 changes: 3 additions & 0 deletions src/Client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@
#include "proto/DevicesSpec.grpc.pb.h"
#include "proto/DevicesSpec.pb.h"
#include <grpcpp/grpcpp.h>
#include <sstream>

using fc::Args;
using fc_pb::Empty;
using grpc::ClientContext;
using grpc::Status;
using grpc::StatusCode;
using std::setw;
using std::stringstream;

namespace fc {
class Client {
Expand Down
90 changes: 71 additions & 19 deletions src/Controller.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
#include "Controller.hpp"

namespace fc {
milliseconds update_interval(500);
bool dynamic = true;
uint smoothing_intervals = 3;
uint top_stickiness_intervals = 2;
uint temp_averaging_intervals = 3;
uint smoothing_intervals = 4;
uint top_stickiness_intervals = 4;
uint temp_averaging_intervals = 8;
} // namespace fc

fc::Controller::Controller(path conf_path_) : config_path(move(conf_path_)) {
load_conf_and_enumerated();

watcher = spawn_watcher();
}

Expand All @@ -24,24 +24,28 @@ FanStatus fc::Controller::status(const string &flabel) const {
: FanStatus::FanStatus_Status_ENABLED;
}

void fc::Controller::enable(fc::FanInterface &f) {
void fc::Controller::enable(fc::FanInterface &f, bool enable_all_dell) {
if (fthreads.count(f.label) > 0) {
LOG(llvl::trace) << f << ": already enabled";
return;
}

// Dell fans can only be enabled/disabled togther
if (f.type() == DevType::DELL && enable_all_dell)
return enable_dell_fans();

if (!f.pre_start_check())
return;

auto update_func = [this, &f]() {
auto update_func = [&f]() {
while (true) {
f.update();
sleep_for(update_interval);
}
};

LOG(llvl::trace) << f.label << ": enabled";
fthreads.try_emplace(f.label, thread(update_func), nullptr);
notify_status_observers(f.label);
}

void fc::Controller::enable_all() {
Expand All @@ -51,31 +55,43 @@ void fc::Controller::enable_all() {
}
}

void fc::Controller::disable(const string &flabel) {
void fc::Controller::disable(const string &flabel, bool disable_all_dell) {
const auto it = fthreads.find(flabel);
if (it != fthreads.end()) {
fthreads.erase(it);
if (const auto fit = devices.fans.find(flabel); fit != devices.fans.end())
fit->second->disable_control();
LOG(llvl::trace) << flabel << ": disabled";
} else {
if (it == fthreads.end()) {
LOG(llvl::error) << flabel << ": failed to find to disable";
return;
}

// Dell fans can only be enabled/disabled togther
if (devices.fans.at(flabel)->type() == DevType::DELL && disable_all_dell)
return disable_dell_fans();

fthreads.erase(it);
if (const auto fit = devices.fans.find(flabel); fit != devices.fans.end())
fit->second->disable_control();

LOG(llvl::trace) << flabel << ": disabled";
notify_status_observers(flabel);
}

void fc::Controller::disable_all() {
vector<string> disabled_fans;
for (const auto &[flabel, fthread] : fthreads)
disabled_fans.push_back(flabel);

fthreads.clear();
for (const auto &flabel : disabled_fans)
notify_status_observers(flabel);

LOG(llvl::trace) << "Disabling all";
}

void fc::Controller::reload() {
// Remove all threads not testing
vector<string> stopped;
for (auto &[key, fthread] : fthreads) {
if (!fthread.is_testing()) {
// fthread.running = false;
if (!fthread.is_testing())
stopped.push_back(key);
}
}

for (const string &key : stopped)
Expand Down Expand Up @@ -136,7 +152,7 @@ void fc::Controller::test(fc::FanInterface &fan, bool forced,

// Only write to file when no other fan are still testing
if (tests_running() == 0)
to_file();
to_file(false);

enable(fan);
};
Expand All @@ -147,6 +163,7 @@ void fc::Controller::test(fc::FanInterface &fan, bool forced,
if (!success)
test(fan, forced, cb);

notify_status_observers(fan.label);
it->second.join();
}

Expand All @@ -157,6 +174,14 @@ size_t fc::Controller::tests_running() const {
return std::accumulate(fthreads.begin(), fthreads.end(), 0, f);
}

void fc::Controller::set_devices(const fc_pb::Devices &devices_) {
disable_all();
devices = fc::Devices(false);
devices.from(devices_);
to_file(false);
enable_all();
}

void fc::Controller::from(const fc_pb::Controller &c) {
from(c.config());
fc::Devices import_devices;
Expand Down Expand Up @@ -205,6 +230,20 @@ void fc::Controller::to(fc_pb::ControllerConfig &c) const {
c.set_temp_averaging_intervals(temp_averaging_intervals);
}

void fc::Controller::enable_dell_fans() {
for (const auto &[fl, f] : devices.fans) {
if (f->type() == DevType::DELL)
enable(*f, false);
}
}

void fc::Controller::disable_dell_fans() {
for (const auto &[fl, f] : devices.fans) {
if (f->type() == DevType::DELL)
disable(fl, false);
}
}

void fc::Controller::load_conf_and_enumerated() {
devices = fc::Devices(true);

Expand Down Expand Up @@ -242,7 +281,10 @@ void fc::Controller::to_file(bool backup) {
to(c);

string out_s;
google::protobuf::TextFormat::PrintToString(c, &out_s);
google::protobuf::TextFormat::Printer printer;
printer.SetUseShortRepeatedPrimitives(true);

printer.PrintToString(c, &out_s);
ofs << out_s;

if (ofs) {
Expand Down Expand Up @@ -280,6 +322,16 @@ void fc::Controller::notify_devices_observers() const {
f(devices);
}

void fc::Controller::notify_status_observers(const string &flabel) {
const auto fit = devices.fans.find(flabel);
if (fit == devices.fans.end())
return;

const FanStatus fstatus = status(flabel);
for (const auto &f : status_observers)
f(*fit->second, fstatus);
}

string fc::Controller::date_time_now() {
std::time_t tt = chrono::system_clock::to_time_t(chrono::system_clock::now());
std::tm tm{};
Expand Down
Loading

0 comments on commit 4673ce5

Please sign in to comment.