tamtamhero / fw-fanctrl Goto Github PK
View Code? Open in Web Editor NEWA simple systemd service to better control Framework Laptop's fan(s)
License: BSD 3-Clause "New" or "Revised" License
A simple systemd service to better control Framework Laptop's fan(s)
License: BSD 3-Clause "New" or "Revised" License
Hi :-),
i just go my Framework 16 in the mail and did setup Manjaro on it. Because of too little fan rpm my whole laptop is (at least for my feeling) quite to warm.
I found your AUR package, but sadly it does not work because your script uses lm_sensors to determine the temperatures. Would you be capable of adding a mode where the temperatures are determined with the ectool? A AUR package for the framrwork-patched version is already available.
Greetings
hasechris
@mdvmeijer went through the work of packaging this up for nix in https://github.com/mdvmeijer/fw-fanctrl-nix.
I am wondering if you'd be open to having any of these changes upstreamed? Note that a fork was necessary too: https://github.com/mdvmeijer/fw-fanctrl.
Curious to hear your thoughts!
Hi,
In the PR #29 , we replaced Most of the Linux dependencies (replacing the file paths with ectool) except for the sockets.
It should now be possible to adapt the script for windows users.
The ectool can be built for win x64 by reproducing the goal in the .gitlab-ci.yml
file (after installing VisualStudio Community 2022 with the C++ and ClangCL package (the installation path may vary slightly))
I have successfully built it in a VM, however since I do not have a native windows installation, I could not fully test if the ectool can properly interacts with the computer hardware.
If you have one, could you please test it on your end, and if everything is ok add the exe to the repo bin folder so I can start the adaptation?
Fedora 37 on 12th Gen Framework laptop.
Running fw-fanctrl
with no arguments after a fresh install:
$ fw-fanctrl
Traceback (most recent call last):
File "/usr/local/bin/fw-fanctrl", line 226, in <module>
main()
File "/usr/local/bin/fw-fanctrl", line 221, in main
fan = FanController(configPath=args.config, strategy=args.strategy)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/bin/fw-fanctrl", line 37, in __init__
with open(configPath, "r") as fp:
^^^^^^^^^^^^^^^^^^^^^
IsADirectoryError: [Errno 21] Is a directory: '.'
So far as I can determine, this is because it is assuming that the config path is the current directory (.), but the configuration file has been installed to /home/[user]/.config/fw-fanctrl
. Issuing fw-fanctrl --config ~/.config/fw-fanctrl/config.json
causes the program to run.
It is not clear from the README or from the help output that a path to a config file is required, and it seems sensible to assume that the config file might be looked for in the location where it was installed to by the installation script. It might even make sense for this to operate at a system level (since the installation script expects to be run as root, and installs a system service), so having a default configuration under the standard Unix /etc
path may be a useful step.
Just updated the AUR package after last commits. Now it's not running. Tried to reinstall the package, no luck
$ fw-fanctrl
Traceback (most recent call last):
File "/usr/bin/fw-fanctrl", line 320, in
main()
File "/usr/bin/fw-fanctrl", line 301, in main
client_socket.connect(COMMANDS_SOCKET_FILE_PATH)
FileNotFoundError: [Errno 2] No such file or directory
Describe the bug
Running the software gives me the errors I shared below, with the software seemingly not working and the system using the default fan curve instead. I'm pretty sure it was working as intended before, but now it's showing these errors.
To Reproduce
Steps to reproduce the behavior:
Expected behavior
Fan control working as configured with no errors in the log.
Screenshots
If applicable, add screenshots to help explain your problem.
Error message
(from systemctl status fw-fanctrl
)
Aug 27 15:20:25 bird-framework python3[9725]: Unable to establish host communication
Aug 27 15:20:25 bird-framework python3[9725]: Couldn't find EC
Aug 27 15:20:25 bird-framework python3[9731]: Error getting I/O privilege: Operation not permitted
Aug 27 15:20:25 bird-framework python3[9731]: Cannot find I2C adapter
Aug 27 15:20:25 bird-framework python3[9731]: Unable to establish host communication
Aug 27 15:20:25 bird-framework python3[9731]: Couldn't find EC
Aug 27 15:20:26 bird-framework python3[9737]: Error getting I/O privilege: Operation not permitted
Aug 27 15:20:26 bird-framework python3[9737]: Cannot find I2C adapter
Aug 27 15:20:26 bird-framework python3[9737]: Unable to establish host communication
Aug 27 15:20:26 bird-framework python3[9737]: Couldn't find EC
Environment (please complete the following information):
{
"defaultStrategy": "bird",
"strategyOnDischarging" : "",
"strategies": {
"bird": {
"fanSpeedUpdateFrequency": 5,
"movingAverageInterval": 40,
"speedCurve": [
{ "temp": 0, "speed": 0 },
{ "temp": 65, "speed": 0 },
{ "temp": 75, "speed": 50 },
{ "temp": 90, "speed": 100 }
]
},
"laziest": {
"fanSpeedUpdateFrequency": 5,
"movingAverageInterval": 40,
"speedCurve": [
{ "temp": 0, "speed": 0 },
{ "temp": 45, "speed": 0 },
{ "temp": 65, "speed": 25 },
{ "temp": 70, "speed": 35 },
{ "temp": 75, "speed": 50 },
{ "temp": 85, "speed": 100 }
]
},
"lazy": {
"fanSpeedUpdateFrequency": 5,
"movingAverageInterval": 30,
"speedCurve": [
{ "temp": 0, "speed": 15 },
{ "temp": 50, "speed": 15 },
{ "temp": 65, "speed": 25 },
{ "temp": 70, "speed": 35 },
{ "temp": 75, "speed": 50 },
{ "temp": 85, "speed": 100 }
]
},
"medium": {
"fanSpeedUpdateFrequency": 5,
"movingAverageInterval": 30,
"speedCurve": [
{ "temp": 0, "speed": 15 },
{ "temp": 40, "speed": 15 },
{ "temp": 60, "speed": 30 },
{ "temp": 70, "speed": 40 },
{ "temp": 75, "speed": 80 },
{ "temp": 85, "speed": 100 }
]
},
"agile": {
"fanSpeedUpdateFrequency": 3,
"movingAverageInterval": 15,
"speedCurve": [
{ "temp": 0, "speed": 15 },
{ "temp": 40, "speed": 15 },
{ "temp": 60, "speed": 30 },
{ "temp": 70, "speed": 40 },
{ "temp": 75, "speed": 80 },
{ "temp": 85, "speed": 100 }
]
},
"very-agile": {
"fanSpeedUpdateFrequency": 2,
"movingAverageInterval": 5,
"speedCurve": [
{ "temp": 0, "speed": 15 },
{ "temp": 40, "speed": 15 },
{ "temp": 60, "speed": 30 },
{ "temp": 70, "speed": 40 },
{ "temp": 75, "speed": 80 },
{ "temp": 85, "speed": 100 }
]
},
"deaf": {
"fanSpeedUpdateFrequency": 2,
"movingAverageInterval": 5,
"speedCurve": [
{ "temp": 0, "speed": 20 },
{ "temp": 40, "speed": 30 },
{ "temp": 50, "speed": 50 },
{ "temp": 60, "speed": 100 }
]
},
"aeolus": {
"fanSpeedUpdateFrequency": 2,
"movingAverageInterval": 5,
"speedCurve": [
{ "temp": 0, "speed": 20 },
{ "temp": 40, "speed": 50 },
{ "temp": 65, "speed": 100 }
]
}
}
}
install.sh
Additional context
Add any other context about the problem here.
i run install bat on windows 11 and did installation successfully
however when i run fw-fanctrl --reload
command in cmd
i get error
File "C:\Windows\System32\fanctrl.py", line 329, in <module>
main()
File "C:\Windows\System32\fanctrl.py", line 308, in main
client_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
^^^^^^^^^^^^^^
AttributeError: module 'socket' has no attribute 'AF_UNIX'
i updated fanctrl.py end to something like this
SOCKETS_FOLDER_PATH = "/run/fw-fanctrl"
COMMANDS_SOCKET_FILE_PATH = ( '127.0.0.1', 12345) # Example IP address and port number
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
client_socket.connect(COMMANDS_SOCKET_FILE_PATH)
client_socket.sendall(' '.join(sys.argv[1:]).encode())
received_data = b""
while True:
data_chunk = client_socket.recv(1024)
if not data_chunk:
break
received_data += data_chunk
# Receive data from the server
data = received_data.decode()
print(data)
if data.startswith("Error:"):
exit(1)
finally:
if client_socket:
client_socket.close()
so what should be COMMANDS_SOCKET_FILE_PATH
for windows ??
I cloned the repository on my Arch Linux system and ran the install script. It works as intended however the fans will keep working after suspend (sleep), Is there a way to make fans stop and start them on resume?
If I use suspend-then-hibernate, e.g. "systemctl suspend-then-hibernate" I observe that it takes up to 90 seconds to successfully suspend, and 90 seconds again to wake up.
If I use suspend e.g. "systemctl suspend" or hybrid-sleep e.g. "systemctl hybrid-sleep", the laptop suspends and wakes in just a couple of seconds.
If I remove /usr/lib/systemd/system-sleep/fw-fanctrl-suspend, the issue goes away. I have no idea why, as running the command "runuser -l myuser -c "fw-fanctrl sleep" returns instantly.
Hi @TamtamHero ,
I would like to refactor the existing command line arguments, complete them with missing essential ones and would appreciate your feedback.
Here are the current arguments (including those in PR #29):
contexts:
option | group | context | description |
---|---|---|---|
<strategy> | run & configure | direct & indirect | the name of the strategy to use |
--run | run | direct | run the service |
--config | run | direct | specify the configuration path |
--no-log | run | direct | disable state logging |
--list-strategies | configure | indirect | print the available strategies |
--query, -q | configure | indirect | print the current strategy name |
--reload, -r | configure | indirect | reload the configuration file |
--pause | configure | indirect | temporarily disable the service |
--resume | configure | indirect | resume the service |
And here are the new ones:
| option | group | context | description |
|---------------------------------------------------------------|-----------------|----------|------------------------------------------|
| --run (?<strategy>) | run | direct | run the service |
| --config | run | direct | specify the configuration path |
| --silent | run | direct | disable state logging |
| --use <strategy> | | indirect | run the service |
| --actual-strategy,-a | | indirect | print the current strategy name |
| --strategy-detail,-d (?<strategy>) | | indirect | list a strategy configuration |
| --list-strategies,--ls,-l | | indirect | print the available strategies |
| --reload-config,--reload, -r | | indirect | reload the configuration file |
| --add-strategy,-A <strategy-name> | add | indirect | add a new strategy to the config |
| --configure-strategy,-C <strategy-name> | configure | indirect | configure a strategy |
| --update-frequency,--uf,-u <update-freq> | add & configure | indirect | set the strategy update frequency |
| --moving-average-interval,--mai,-m <moving-average-interval> | add & configure | indirect | set the strategy moving average interval |
| --curve-point,--cp,-c <temp>:<fan-duty> | add & configure | indirect | set a point in the curve |
| --delete-strategy,-D <strategy-name> | | indirect | delete a strategy |
| --pause | | indirect | temporarily disable the service |
| --resume | | indirect | resume the service |
Edit: After much thoughts, I think we should use subcommands when possible, as they are more intuitive.
run
: direct : run the service. (use reset
to reset to the default strategy)argument | description |
---|---|
strategy |
name of the strategy to use e.g: "lazy". (use print strategies to list available strategies). (optional) |
--config , -c |
config file path. (default: /etc/fw-fanctrl/config.json ) |
--silent , -s |
disable printing speed/temp status to stdout |
reload
: indirect : reload configurationreset
: indirect : reset the current strategy to the default oneset-default
: indirect : set the default strategyargument | description |
---|---|
strategy |
name of the strategy to use e.g: "lazy". (use print strategies to list available strategies) |
--discharge , --d |
is the default for discharging strategy |
remove-default
: indirect : remove the default strategyargument | description |
---|---|
--discharge , --d |
is the default for discharging strategy |
add
: indirect : add a new strategyargument | description |
---|---|
strategy |
name of the strategy to use e.g: "lazy". (use print strategies to list available strategies) |
curve_point ... |
a point in the temperature curve in the format: temp:speed |
--update-frequency , --uf , -u |
time interval between every temperature update. (min: 1. default: 5) |
--average-interval , --ai , -a |
number of seconds on which the moving average of temperature is computed. (min: 0. default: 20) |
configure
: indirect : configure an existing strategyargument | description |
---|---|
strategy |
name of the strategy to use e.g: "lazy". (use print strategies to list available strategies) |
curve_point ... |
a point in the temperature curve in the format: temp:speed . (optional) |
--update-frequency , --uf , -u |
time interval between every temperature update. (min: 1. default: 5) |
--average-interval , --ai , -a |
number of seconds on which the moving average of temperature is computed. (min: 0. default: 20) |
delete
: direct : delete an existing strategyargument | description |
---|---|
strategy |
name of the strategy to use e.g: "lazy". (use print strategies to list available strategies) |
pause
: direct : pause the serviceresume
: resume : pause the serviceprint
: direct : print desired informationargument (OR) | description |
---|---|
current-strategy |
print the current strategy |
strategy-details strategy |
print the details of the specified strategy |
strategies |
list the available strategies |
The aim is to make them more intuitive and organised, and to achieve this many of them will have to be renamed/removed and users will have to change the way they use the actual commands.
What are your thoughts on this?
Should we go for it or add a deprecation warning for now?
Fedora 37 on 12th Gen Framework laptop.
Running fw-fanctrl --config ~/.config/fw-fanctrl/config.json
results in the following output:
Cannot open lockfile /run/lock/cros_ec_lockCould not acquire GEC lock.
speed: 15% temp: 42.5°C movingAverage: 42.5°C
speed: 15% temp: 42.0°C movingAverage: 42.48°C
speed: 15% temp: 40.666666666666664°C movingAverage: 42.42°C
Cannot open lockfile /run/lock/cros_ec_lockCould not acquire GEC lock.
speed: 15% temp: 41.166666666666664°C movingAverage: 42.38°C
speed: 15% temp: 40.916666666666664°C movingAverage: 42.33°C
speed: 15% temp: 40.333333333333336°C movingAverage: 42.25°C
speed: 15% temp: 41.75°C movingAverage: 42.23°C
speed: 15% temp: 40.416666666666664°C movingAverage: 42.16°C
Cannot open lockfile /run/lock/cros_ec_lockCould not acquire GEC lock.
speed: 15% temp: 40.833333333333336°C movingAverage: 42.1°C
Running the same command as root (via sudo) does not have an issue with the lockfile (which is owned by root).
Should this utility only be run as root? If so, should the configuration file be installed on a per-user basis?
When running fw-fanctrl --list-strategies
, no output is provided. This behavior is consistent, provides no error message, and persists after reinstalling. I have confirmed that the configuration file exists in the default location.
Environment
It would be nice if there was a "maximum acceptable temperature", and if it ever detects that the temperature is past that, it forcefully sets the fans to 100% until it goes back down, independent of the moving average. This would allow for having a relatively wide interval without fear of severe overheating if the CPU starts getting too hot.
Would you like to be involved in the development?
Yes, though I'd need some pointers on how this should be configured (per-profile? global? naming?) if I'm going to be the one programming.
Hi there,
As stated in this project README, fw-fanctrl
uses fw-ectool to change parameters in FrameWork's embedded controller (EC).
the link refers to the DHowett/fw-ectool project, which is a fork of the Framework team's FrameworkComputer/EmbeddedController project.
The main concern here is that the DHowett/fw-ectool project is a whopping 10098 commits behind the official project.
I imagine that there are reasons for using DHowett/fw-ectool instead of FrameworkComputer/EmbeddedController, but I cannot seem to find any information or documentation about it either in DHowett/fw-ectool or in this project and would appreciate a bit of context about this choice.
Thank you and have a great day.
Hello,
I have the new FW AMD 13 inch laptop and I checked out the changes made to support AMD here, but it looks like my output for lm_sensors is missing acpitz-acpi-0
that is required for fw-fanctrl.
Here is my sensors -j
output:
{
"mt7921_phy0-pci-0100":{
"Adapter": "PCI adapter",
"temp1":{
"temp1_input": 48.000
}
},
"ucsi_source_psy_USBC000:004-isa-0000":{
"Adapter": "ISA adapter",
"in0":{
"in0_input": 0.000,
"in0_min": 0.000,
"in0_max": 0.000
},
"curr1":{
"curr1_input": 0.000,
"curr1_max": 0.000
}
},
"ucsi_source_psy_USBC000:002-isa-0000":{
"Adapter": "ISA adapter",
"in0":{
"in0_input": 5.000,
"in0_min": 5.000,
"in0_max": 5.000
},
"curr1":{
"curr1_input": 0.000,
"curr1_max": 1.500
}
},
"nvme-pci-0200":{
"Adapter": "PCI adapter",
"Composite":{
"temp1_input": 39.850,
"temp1_max": 84.850,
"temp1_min": -0.150,
"temp1_crit": 94.850,
"temp1_alarm": 0.000
},
"Sensor 1":{
"temp2_input": 39.850,
"temp2_max": 65261.850,
"temp2_min": -273.150
},
"Sensor 2":{
"temp3_input": 41.850,
"temp3_max": 65261.850,
"temp3_min": -273.150
},
"Sensor 8":{
"temp9_input": 39.850,
"temp9_max": 65261.850,
"temp9_min": -273.150
}
},
"amdgpu-pci-c100":{
"Adapter": "PCI adapter",
"vddgfx":{
"in0_input": 1.284
},
"vddnb":{
"in1_input": 0.806
},
"edge":{
"temp1_input": 45.000
},
"PPT":{
"power1_average": 8.236,
"power1_input": 23.184
}
},
"k10temp-pci-00c3":{
"Adapter": "PCI adapter",
"Tctl":{
"temp1_input": 47.750
}
},
"ucsi_source_psy_USBC000:003-isa-0000":{
"Adapter": "ISA adapter",
"in0":{
"in0_input": 5.000,
"in0_min": 5.000,
"in0_max": 5.000
},
"curr1":{
"curr1_input": 0.000,
"curr1_max": 1.500
}
},
"ucsi_source_psy_USBC000:001-isa-0000":{
"Adapter": "ISA adapter",
"in0":{
"in0_input": 0.000,
"in0_min": 0.000,
"in0_max": 0.000
},
"curr1":{
"curr1_input": 0.410,
"curr1_max": 0.000
}
},
"BAT1-acpi-0":{
"Adapter": "ACPI interface",
"in0":{
"in0_input": 16.221
},
"curr1":{
"curr1_input": 0.000
}
}
}
In fanctrl.py, i tried using k10temp-pci-00c3
instead of acpitz-acpi-0
and it seems to work somewhat. It seems like both the 16 inch and 13 inch AMD laptops both contain k10temp-pci-00c3
, would it be possible to add support for this?
Thanks.
Edit:
It does look like k10temp should be the correct sensor reading to use for current Ryzen AMD processors.
The fw-fanctrl tool was working ok but after some intensive compilation recently I detect that is reading the temperature from the wrong sensor, provoking that the fan never goes to 100% on max load, making the CPU throttle and the chasis unconformable to the touch...
OS: Manjaro
Kernel: 6.9.0-1-MANJARO
Host: Laptop 13 (AMD Ryzen 7040Series) (A7)
lm-sensors output:
❯ sensors
ucsi_source_psy_USBC000:002-isa-0000
Adapter: ISA adapter
in0: 5.00 V (min = +5.00 V, max = +5.00 V)
curr1: 0.00 A (max = +1.50 A)
iwlwifi_1-virtual-0
Adapter: Virtual device
temp1: +34.0°C
ucsi_source_psy_USBC000:004-isa-0000
Adapter: ISA adapter
in0: 20.00 V (min = +5.00 V, max = +38.80 V)
curr1: 5.00 A (max = +3.56 A)
amdgpu-pci-c100
Adapter: PCI adapter
vddgfx: 838.00 mV
vddnb: 765.00 mV
edge: +87.0°C
PPT: 28.22 W (avg = 28.01 W)
BAT1-acpi-0
Adapter: ACPI interface
in0: 17.70 V
curr1: 0.00 A
ucsi_source_psy_USBC000:003-isa-0000
Adapter: ISA adapter
in0: 0.00 V (min = +0.00 V, max = +0.00 V)
curr1: 680.00 mA (max = +0.00 A)
ucsi_source_psy_USBC000:001-isa-0000
Adapter: ISA adapter
in0: 0.00 V (min = +0.00 V, max = +0.00 V)
curr1: 0.00 A (max = +0.00 A)
k10temp-pci-00c3
Adapter: PCI adapter
Tctl: +88.1°C
nvme-pci-0200
Adapter: PCI adapter
Composite: +39.9°C (low = -273.1°C, high = +89.8°C)
(crit = +94.8°C)
Sensor 1: +39.9°C (low = -273.1°C, high = +65261.8°C)
Sensor 2: +35.9°C (low = -273.1°C, high = +65261.8°C)
acpitz-acpi-0
Adapter: ACPI interface
temp1: +50.8°C
temp2: +55.8°C
temp3: +45.8°C
temp4: +87.8°C
fw-fanctrl output for the same temp:
speed: 19% temp: 47.8°C movingAverage: 46.3°C
speed: 19% temp: 47.8°C movingAverage: 46.4°C
speed: 19% temp: 47.8°C movingAverage: 46.5°C
speed: 19% temp: 47.8°C movingAverage: 46.57°C
speed: 19% temp: 47.8°C movingAverage: 46.63°C
speed: 19% temp: 47.8°C movingAverage: 46.7°C
speed: 19% temp: 48.8°C movingAverage: 46.8°C
speed: 19% temp: 47.8°C movingAverage: 46.87°C
speed: 19% temp: 47.8°C movingAverage: 46.93°C
speed: 20% temp: 48.8°C movingAverage: 47.03°C
speed: 20% temp: 48.8°C movingAverage: 47.13°C
speed: 20% temp: 48.8°C movingAverage: 47.23°C
speed: 20% temp: 48.8°C movingAverage: 47.33°C
speed: 20% temp: 48.8°C movingAverage: 47.43°C
speed: 20% temp: 48.8°C movingAverage: 47.53°C
speed: 20% temp: 48.8°C movingAverage: 47.63°C
speed: 20% temp: 48.8°C movingAverage: 47.73°C
speed: 20% temp: 48.8°C movingAverage: 47.8°C
speed: 20% temp: 48.8°C movingAverage: 47.87°C
speed: 20% temp: 48.8°C movingAverage: 47.93°C
speed: 20% temp: 48.8°C movingAverage: 48.0°C
speed: 20% temp: 48.8°C movingAverage: 48.07°C
speed: 20% temp: 48.8°C movingAverage: 48.13°C
speed: 20% temp: 49.8°C movingAverage: 48.2°C
speed: 21% temp: 49.8°C movingAverage: 48.3°C
speed: 21% temp: 49.8°C movingAverage: 48.4°C
speed: 21% temp: 49.8°C movingAverage: 48.5°C
speed: 21% temp: 49.8°C movingAverage: 48.6°C
speed: 21% temp: 49.8°C movingAverage: 48.7°C
speed: 21% temp: 49.8°C movingAverage: 48.77°C
speed: 21% temp: 49.8°C movingAverage: 48.83°C
speed: 21% temp: 49.8°C movingAverage: 48.9°C
speed: 21% temp: 49.8°C movingAverage: 48.97°C
speed: 21% temp: 49.8°C movingAverage: 49.03°C
Please let me know if I can help with extra info. Thanks!
I wish we can do things like fw-fanctrl lazy
or fw-fanctrl medium
Is your feature request related to a problem? Please describe.
Currently there are only two supported options for the print
command: list
and current
. At the moment I'm not using separate strategies for charging and discharging so, these two options aren't particularly relevant for me. What I am interested in printing is the current fan speed percentage and/or exact RPM.
Describe the solution you'd like
Additional supported arguments for the print
command to monitor the current fan speed, such as:
$ fw-fanctrl print speed_percentage
23
and/or
$ fw-fanctrl print speed_rpm
672
No strong preferences on the naming of the arguments
Describe alternatives you've considered
I could get the current fan speed by extracting it from the log messages, but the current fan speed feels like it should be a valid option supported by the script
Additional context
My exact use case is to add a custom fan speed module to my waybar setup. Having a concise command able to print the value to display makes it much more simple to configure:
{
"custom/fan-speed": {
"exec": "fw-fanctrl print speed_percentage",
"format": "{}%",
"interval": 5
}
}
Would you like to be involved in the development?
Sure! Python is not my strong suit, though. I believe I could come up with an implementation that does work, but it might not be the "right" way to do it
Is there a way to fully disable this tool and resort to the default fan control (without uninstalling)?
If there is, it would be awesome to include it in the README.
If there's not, allow this to be a feature request for such a feature.
Describe the bug
fw-fanctrl
often crashes, with the seemingly relevant error being EC returned error result code 1
(full report below). This usually happens after somewhere between a few seconds and 10 minutes I think (these are simply guesses based on my own time perception). It sounds like this might not be an error with fw-fanctrl
to me, based on the fact it's saying "EC returned error...", but I imagine the error handling could certainly be more graceful (e.g. the UTF-8 decode error shown in the full report, which I interpret as not being the root cause of the crash).
To Reproduce
I'm not entirely sure; clearly this is something unique to my setup, or it would be happening to everyone. But however you reproduce EC returning an error code 1 must be how.
Error message
$ sudo fw-fanctrl --run
speed: 15%, temp: 31°C, movingAverageTemp: 31.0°C, effectureTemp: 31.0°C
speed: 15%, temp: 31°C, movingAverageTemp: 31.0°C, effectureTemp: 31.0°C
speed: 15%, temp: 30°C, movingAverageTemp: 30.7°C, effectureTemp: 30°C
EC returned error result code 1
EC response has invalid checksum
EC returned too much data
Traceback (most recent call last):
File "/usr/bin/fw-fanctrl", line 329, in <module>
main()
File "/usr/bin/fw-fanctrl", line 306, in main
fan.run(debug=not args.no_log)
File "/usr/bin/fw-fanctrl", line 252, in run
self.printState()
File "/usr/bin/fw-fanctrl", line 234, in printState
currentTemperture = self.getActualTemperature()
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/bin/fw-fanctrl", line 189, in getActualTemperature
rawOut = subprocess.run(bashCommand, stdout=subprocess.PIPE, shell=True, text=True).stdout
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.12/subprocess.py", line 550, in run
stdout, stderr = process.communicate(input, timeout=timeout)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.12/subprocess.py", line 1196, in communicate
stdout = self.stdout.read()
^^^^^^^^^^^^^^^^^^
File "<frozen codecs>", line 322, in decode
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfd in position 143: invalid start byte
Environment (please complete the following information):
fw-fanctrl-git r45.dc6558e-1
(AUR package; presumably commit dc6558e)paru -S fw-fanctrl-git
)Hi,
Would you be in favor of using pipfile for dependency management over the traditional requirements.txt
?
This would mainly allow us to keep production and dev dependencies separate, as well as requiring a minimum Python version.
Here is the documentation if you want to know more about it.
Framework 13th gen, seems like sometimes after it suspends/hibernates or runs for a few days something goes haywire and it goes up to 100% cpu usage (as reported by top, so only one thread.) Restarting the service solves this. Next time it happens I'll try to collect some logs.
Describe the bug
The installation script attempts to assume control over the systemd services it installs by trying to stop them if they are running. This is fine for systems directly calling the install script, though it introduces issues during AUR package build. It is a better idea to have this happen in post-install, and for the AUR package this does not make sense anyways until the actual package installation runs (where pacman's hooks manage the systemd services).
To Reproduce
Steps to reproduce the behavior:
Expected behavior
It should copy the files and create the package successfully without touching any host services.
Error message
==> Starting package()...
creating '/home/icedream/Documents/Source/Git/aur.archlinux.org/fw-fanctrl-git/pkg/fw-fanctrl-git/usr/lib/systemd/system'
creating services
stopping [fw-fanctrl]
Failed to stop fw-fanctrl.service: Access denied
See system logs and 'systemctl status fw-fanctrl.service' for details.
This also pops up a graphical request to allow access to the host systemd.
Environment (please complete the following information):
Hi, as stated here by @dariov1988 , we should not embed binaries into the project, but rather fetch them from the official source.
The build artifacts for ectool can be found here.
This is an open question:
Do you have any recommendations on how we should fetch, extract and install the artifacts for this project?
Describe the bug
When I ran the program I got the error that libftdi1.so.2 was not installed.
To Reproduce
Steps to reproduce the behavior:
Install on system without libftdi1.
Expected behavior
I believe this library should be mentioned in the README because it is a dependency of the program.
Environment (please complete the following information):
Describe the bug
The error message below happened. Right before the timestamps of the logs, the computer showed 0% battery and then shutdown due to critically-low battery.
DeflateAwning@host ~> sudo systemctl status fw-fanctrl.service
[sudo] password for DeflateAwning:
● fw-fanctrl.service - Framework Fan Controller
Loaded: loaded (/lib/systemd/system/fw-fanctrl.service; enabled; vendor preset: enabled)
Active: active (running) since Sun 2024-06-30 14:27:12 PDT; 12min ago
Main PID: 2166 (python3)
Tasks: 2 (limit: 76620)
Memory: 6.8M
CPU: 21.528s
CGroup: /system.slice/fw-fanctrl.service
└─2166 /usr/bin/python3 /usr/bin/fw-fanctrl --run --config /etc/fw-fanctrl/config.json --no-log
Jun 30 14:29:04 host python3[4114]: Unable to establish host communication
Jun 30 14:29:04 host python3[4114]: Couldn't find EC
Jun 30 14:31:13 host python3[4799]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknow>
Jun 30 14:32:54 host python3[7435]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknow>
Jun 30 14:35:19 host python3[8437]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
Jun 30 14:36:44 host python3[8940]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
Jun 30 14:36:44 host python3[8940]: EC result 7 (INVALID_CHECKSUM)
Jun 30 14:37:06 host python3[9072]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
Jun 30 14:37:43 host python3[9250]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknow>
Jun 30 14:38:41 host python3[9598]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
Environment (please complete the following information):
Additional context
Crashes in a tool which controls system temperature are very bad.
In my opinion, this tool should be marked as Unstable in the README, based on this experience.
Fedora 36 kernel 6.2.12., framework gen 12th.
Just notice that despite the service was in running state it was not working - CPU got 100 C and start throttling.
Here is journalctl:
kwi 27 08:56:57 framework systemd[1]: Started fw-fanctrl.service - FrameWork Fan Controller.
kwi 27 08:56:57 framework systemd[1]: fw-fanctrl.service: Consumed 37min 54.503s CPU time.
kwi 27 08:56:57 framework systemd[1]: Stopped fw-fanctrl.service - FrameWork Fan Controller.
kwi 27 08:56:57 framework systemd[1]: fw-fanctrl.service: Deactivated successfully.
kwi 27 08:56:57 framework systemd[1]: Stopping fw-fanctrl.service - FrameWork Fan Controller...
kwi 26 09:12:51 framework python3[15106]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
kwi 26 08:44:58 framework python3[10200]: ERROR: Can't get value of subfeature curr1_input: Can't read
kwi 26 08:16:29 framework systemd[1]: Started fw-fanctrl.service - FrameWork Fan Controller.
Before the time I can notice that the service consume a lot of CPU and also have different errors (which probably is why the FW was so quite) :
-- Boot 644552e41ada4807a69228efd7b6c557 --
kwi 26 08:14:28 framework systemd[1]: fw-fanctrl.service: Consumed 6.343s CPU time.
kwi 26 08:14:28 framework systemd[1]: Stopped fw-fanctrl.service - FrameWork Fan Controller.
kwi 26 08:14:28 framework systemd[1]: fw-fanctrl.service: Deactivated successfully.
kwi 26 08:14:28 framework systemd[1]: Stopping fw-fanctrl.service - FrameWork Fan Controller...
kwi 25 21:33:42 framework systemd[1]: Started fw-fanctrl.service - FrameWork Fan Controller.
-- Boot 6cf6a57ede98488c8200bad27bfb9ddb --
kwi 25 20:40:55 framework systemd[1]: fw-fanctrl.service: Consumed 43min 33.261s CPU time.
kwi 25 20:40:55 framework systemd[1]: Stopped fw-fanctrl.service - FrameWork Fan Controller.
kwi 25 20:40:55 framework systemd[1]: fw-fanctrl.service: Deactivated successfully.
kwi 25 20:40:55 framework systemd[1]: Stopping fw-fanctrl.service - FrameWork Fan Controller...
kwi 24 11:29:44 framework python3[523387]: ERROR: Can't get value of subfeature curr1_input: Can't read
kwi 24 11:08:51 framework python3[519305]: EC result 1 (INVALID_COMMAND)
kwi 24 11:08:51 framework python3[519305]: EC result 7 (INVALID_CHECKSUM)
kwi 24 11:08:51 framework python3[519305]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
kwi 24 10:28:12 framework python3[511159]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknown>)
kwi 24 10:28:12 framework python3[511159]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
kwi 24 10:28:12 framework python3[511159]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknown>)
kwi 20 17:20:16 framework python3[356320]: EC result 7 (INVALID_CHECKSUM)
kwi 20 17:20:16 framework python3[356320]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
kwi 20 16:28:47 framework python3[344826]: EC result 7 (INVALID_CHECKSUM)
kwi 20 09:53:07 framework python3[256432]: ERROR: Can't get value of subfeature temp1_input: Can't read
kwi 20 09:53:06 framework python3[256410]: ERROR: Can't get value of subfeature temp1_input: Can't read
kwi 20 09:53:05 framework python3[256404]: ERROR: Can't get value of subfeature temp1_input: Can't read
kwi 20 09:53:04 framework python3[256397]: ERROR: Can't get value of subfeature temp1_input: Can't read
kwi 19 21:08:00 framework python3[243779]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
kwi 19 15:09:25 framework python3[185589]: EC result 7 (INVALID_CHECKSUM)
kwi 18 09:21:10 framework systemd[1]: Started fw-fanctrl.service - FrameWork Fan Controller.
-- Boot 79d24f8d0cbe49b4bc49b311bc4f5179 --
kwi 18 09:18:12 framework systemd[1]: fw-fanctrl.service: Consumed 31min 11.310s CPU time.
kwi 18 09:18:12 framework systemd[1]: Stopped fw-fanctrl.service - FrameWork Fan Controller.
kwi 18 09:18:12 framework systemd[1]: fw-fanctrl.service: Deactivated successfully.
kwi 18 09:18:12 framework systemd[1]: Stopping fw-fanctrl.service - FrameWork Fan Controller...
kwi 17 15:55:44 framework python3[211165]: ERROR: Can't get value of subfeature curr1_input: Can't read
kwi 17 11:41:54 framework python3[160535]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
kwi 17 11:37:52 framework python3[159695]: EC returned error result code 7
kwi 17 10:59:32 framework python3[151728]: EC returned error result code 7
kwi 17 10:59:32 framework python3[151728]: EC returned error result code 7
kwi 17 10:42:06 framework python3[148010]: EC returned error result code 7
kwi 17 10:42:06 framework python3[148010]: EC returned error result code 7
kwi 17 10:42:06 framework python3[148010]: EC returned error result code 7
kwi 14 15:38:27 framework python3[86713]: EC result 1 (INVALID_COMMAND)
kwi 14 15:38:27 framework python3[86713]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknown>)
kwi 14 15:38:27 framework python3[86713]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
kwi 14 13:15:24 framework python3[53632]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknown>)
kwi 14 13:15:24 framework python3[53632]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
kwi 14 12:27:58 framework python3[44461]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
kwi 14 11:39:03 framework python3[33655]: EC result 7 (INVALID_CHECKSUM)
kwi 14 11:39:03 framework python3[33655]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknown>)
kwi 14 11:39:03 framework python3[33655]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknown>)
kwi 14 11:12:12 framework python3[26977]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknown>)
kwi 14 11:12:12 framework python3[26977]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
kwi 14 10:48:08 framework python3[21264]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknown>)
kwi 14 09:24:52 framework systemd[1]: Started fw-fanctrl.service - FrameWork Fan Controller.
-- Boot 41a8abc55a1f43c1a2f6c4b36ff6a9ea --
kwi 14 09:21:30 framework systemd[1]: fw-fanctrl.service: Consumed 1h 15min 31.659s CPU time.
kwi 14 09:21:30 framework systemd[1]: Stopped fw-fanctrl.service - FrameWork Fan Controller.
kwi 14 09:21:30 framework systemd[1]: fw-fanctrl.service: Deactivated successfully.
kwi 14 09:21:30 framework systemd[1]: Stopping fw-fanctrl.service - FrameWork Fan Controller...
kwi 13 16:56:15 framework python3[557993]: ERROR: Can't get value of subfeature curr1_input: Can't read
kwi 13 15:38:44 framework python3[539256]: EC result 1 (INVALID_COMMAND)
kwi 13 15:38:44 framework python3[539256]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknown>)
kwi 13 15:38:44 framework python3[539256]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
kwi 13 15:33:57 framework python3[538037]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
kwi 13 15:22:00 framework python3[535332]: Couldn't find EC
kwi 13 15:22:00 framework python3[535332]: Unable to establish host communication
kwi 13 15:22:00 framework python3[535332]: Cannot find I2C adapter
kwi 13 15:22:00 framework python3[535332]: Missing Chromium EC memory map.
kwi 13 13:41:54 framework python3[512914]: ERROR: Can't get value of subfeature curr1_input: Can't read
kwi 13 13:20:43 framework python3[508422]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknown>)
kwi 13 13:20:43 framework python3[508422]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknown>)
kwi 13 13:09:56 framework python3[506285]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknown>)
kwi 13 13:09:56 framework python3[506285]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
kwi 13 12:34:42 framework python3[498462]: EC result 1 (INVALID_COMMAND)
kwi 13 12:34:42 framework python3[498462]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknown>)
kwi 13 12:34:42 framework python3[498462]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
kwi 13 11:47:57 framework python3[488192]: EC result 1 (INVALID_COMMAND)
kwi 13 11:47:57 framework python3[488192]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknown>)
kwi 13 11:08:33 framework python3[479337]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
kwi 12 17:49:56 framework python3[394215]: EC result 1 (INVALID_COMMAND)
kwi 12 17:49:56 framework python3[394215]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
kwi 12 14:29:58 framework python3[348437]: ERROR: Can't get value of subfeature curr1_input: Can't read
kwi 12 14:17:51 framework python3[345813]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
kwi 12 14:17:51 framework python3[345813]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknown>)
kwi 11 16:38:44 framework python3[238503]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknown>)
kwi 11 16:04:35 framework python3[230894]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
kwi 11 16:03:33 framework python3[230712]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
kwi 11 09:48:56 framework python3[144844]: EC result 7 (INVALID_CHECKSUM)
kwi 11 09:48:56 framework python3[144844]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknown>)
kwi 11 09:07:27 framework python3[133445]: EC result 7 (INVALID_CHECKSUM)
kwi 07 10:24:49 framework python3[21897]: EC result 7 (INVALID_CHECKSUM)
kwi 07 09:53:29 framework python3[15828]: ERROR: Can't get value of subfeature curr1_input: Can't read
kwi 07 09:43:50 framework python3[13112]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknown>)
kwi 07 09:43:50 framework python3[13112]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknown>)
kwi 07 09:43:50 framework python3[13112]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknown>)
kwi 07 03:37:37 framework python3[1565]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknown>)
kwi 07 03:37:34 framework systemd[1]: Started fw-fanctrl.service - FrameWork Fan Controller.
-- Boot e72b7f5318814a8c908d915cda740caf --
kwi 07 03:36:33 framework systemd[1]: Stopped fw-fanctrl.service - FrameWork Fan Controller.
kwi 07 03:36:33 framework systemd[1]: fw-fanctrl.service: Deactivated successfully.
kwi 07 03:36:33 framework systemd[1]: Stopping fw-fanctrl.service - FrameWork Fan Controller...
kwi 07 03:36:28 framework systemd[1]: Started fw-fanctrl.service - FrameWork Fan Controller.
-- Boot ca589b949ee14a91a61cb84427d76079 --
kwi 07 03:35:31 framework systemd[1]: fw-fanctrl.service: Consumed 14min 25.623s CPU time.
kwi 07 03:35:31 framework systemd[1]: Stopped fw-fanctrl.service - FrameWork Fan Controller.
kwi 07 03:35:31 framework systemd[1]: fw-fanctrl.service: Deactivated successfully.
kwi 07 03:35:31 framework systemd[1]: Stopping fw-fanctrl.service - FrameWork Fan Controller...
kwi 06 21:37:08 framework python3[240507]: EC result 7 (INVALID_CHECKSUM)
kwi 06 21:16:46 framework python3[237256]: EC result 7 (INVALID_CHECKSUM)
kwi 06 18:46:31 framework python3[219301]: EC result 7 (INVALID_CHECKSUM)
kwi 06 18:23:03 framework python3[215196]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
kwi 06 18:23:03 framework python3[215196]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknown>)
kwi 06 18:23:03 framework python3[215196]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknown>)
kwi 06 18:10:56 framework python3[213402]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
kwi 06 18:03:31 framework python3[212246]: EC result 7 (INVALID_CHECKSUM)
kwi 06 17:50:01 framework python3[209570]: EC result 7 (INVALID_CHECKSUM)
kwi 06 17:39:56 framework python3[208019]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
kwi 06 15:43:33 framework python3[187609]: EC result 7 (INVALID_CHECKSUM)
kwi 06 08:50:07 framework python3[115943]: EC result 7 (INVALID_CHECKSUM)
kwi 05 20:57:36 framework python3[114441]: EC result 7 (INVALID_CHECKSUM)
kwi 05 20:57:36 framework python3[114441]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknown>)
kwi 05 18:36:31 framework python3[94646]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
kwi 05 18:16:23 framework python3[91727]: EC result 7 (INVALID_CHECKSUM)
kwi 05 17:53:04 framework python3[88044]: ioctl -1, errno 74 (Bad message), EC result 255 (<unknown>)
kwi 05 16:29:18 framework python3[73106]: ERROR: Can't get value of subfeature temp1_input: I/O error
kwi 05 16:28:34 framework python3[72990]: ERROR: Can't get value of subfeature temp1_input: I/O error
kwi 05 16:08:41 framework python3[69710]: ERROR: Can't get value of subfeature temp1_input: I/O error
kwi 05 15:43:41 framework python3[65511]: ERROR: Can't get value of subfeature temp1_input: I/O error
kwi 05 15:43:33 framework python3[65500]: ERROR: Can't get value of subfeature temp1_input: I/O error
kwi 05 14:37:19 framework python3[54951]: ioctl -1, errno 90 (Message too long), EC result 255 (<unknown>)
kwi 05 11:04:24 framework python3[19757]: EC result 7 (INVALID_CHECKSUM)
kwi 05 09:34:47 framework systemd[1]: Started fw-fanctrl.service - FrameWork Fan Controller.
Hi,
Currently, the installation process manually moves the Python script to /usr/bin/fw-fanctrl
(or other configured path).
This is a manual non-standard process that is only valid for single-file scripts.
I think that we should use the "standard" way of doing this with a setup.py
file descriptor and install it with pip install
instead.
This method uses the setuptools.
Several formats for the setup file are availablepyproject.toml
,setup.cfg
andsetup.py
.
The exact format is yet to be decided.
This would allow us to split the already large (633 lines) script file into modules, as well as allow for versioning and possible future dependencies and developement dependencies (e.g. a file formatter or tests to ensure uniformity and stability).
What do you think about this this?
This is a public poll, feel free to give your opinion and discuss this proposal even if you are not an active developer on this project 😉
Describe the bug
Sleep hook causes a hang when coming out of suspend. Also reported at systemd/systemd#33020 and https://bbs.archlinux.org/viewtopic.php?pid=2177336#p2177336.
To Reproduce
Expected behavior
The system should resume from sleep instantly.
Screenshots
If applicable, add screenshots to help explain your problem.
Error message
Jun 10 22:40:56 <REDACTED> runuser[56917]: pam_unix(runuser-l:session): session opened for user root(uid=0) by root(uid=0)
Jun 10 22:41:26 <REDACTED> runuser[56812]: pam_systemd(runuser-l:session): Failed to create session: Connection timed out
Jun 10 22:41:26 <REDACTED> runuser[56812]: pam_unix(runuser-l:session): session closed for user root
Environment (please complete the following information):
yay -S fw-fanctrl-git
Additional context
Removing the sleep hook solves the problem.
When I start the service, I see this in the logs:
5:39 PM Couldn't find EC python3
5:39 PM Unable to establish host communication python3
5:39 PM Cannot find I2C adapter python3
5:39 PM Missing Chromium EC memory map. python3
5:39 PM Started fw-fanctrl.service - FrameWork Fan Controller. systemd
It then continues to repeat this ad infinitum
Here's my config file from ~/.config/fw-fanctrl:
config.json
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.