1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 cfg = config.services.octoprint;
8
9 baseConfig = {
10 plugins.curalegacy.cura_engine = "${pkgs.curaengine_stable}/bin/CuraEngine";
11 server.host = cfg.host;
12 server.port = cfg.port;
13 webcam.ffmpeg = "${pkgs.ffmpeg.bin}/bin/ffmpeg";
14 };
15
16 fullConfig = recursiveUpdate cfg.extraConfig baseConfig;
17
18 cfgUpdate = pkgs.writeText "octoprint-config.yaml" (builtins.toJSON fullConfig);
19
20 pluginsEnv = package.python.withPackages (ps: [ps.octoprint] ++ (cfg.plugins ps));
21
22 package = pkgs.octoprint;
23
24in
25{
26 ##### interface
27
28 options = {
29
30 services.octoprint = {
31
32 enable = mkEnableOption (lib.mdDoc "OctoPrint, web interface for 3D printers");
33
34 host = mkOption {
35 type = types.str;
36 default = "0.0.0.0";
37 description = lib.mdDoc ''
38 Host to bind OctoPrint to.
39 '';
40 };
41
42 port = mkOption {
43 type = types.port;
44 default = 5000;
45 description = lib.mdDoc ''
46 Port to bind OctoPrint to.
47 '';
48 };
49
50 user = mkOption {
51 type = types.str;
52 default = "octoprint";
53 description = lib.mdDoc "User for the daemon.";
54 };
55
56 group = mkOption {
57 type = types.str;
58 default = "octoprint";
59 description = lib.mdDoc "Group for the daemon.";
60 };
61
62 stateDir = mkOption {
63 type = types.path;
64 default = "/var/lib/octoprint";
65 description = lib.mdDoc "State directory of the daemon.";
66 };
67
68 plugins = mkOption {
69 type = types.functionTo (types.listOf types.package);
70 default = plugins: [];
71 defaultText = literalExpression "plugins: []";
72 example = literalExpression "plugins: with plugins; [ themeify stlviewer ]";
73 description = lib.mdDoc "Additional plugins to be used. Available plugins are passed through the plugins input.";
74 };
75
76 extraConfig = mkOption {
77 type = types.attrs;
78 default = {};
79 description = lib.mdDoc "Extra options which are added to OctoPrint's YAML configuration file.";
80 };
81
82 };
83
84 };
85
86 ##### implementation
87
88 config = mkIf cfg.enable {
89
90 users.users = optionalAttrs (cfg.user == "octoprint") {
91 octoprint = {
92 group = cfg.group;
93 uid = config.ids.uids.octoprint;
94 };
95 };
96
97 users.groups = optionalAttrs (cfg.group == "octoprint") {
98 octoprint.gid = config.ids.gids.octoprint;
99 };
100
101 systemd.tmpfiles.rules = [
102 "d '${cfg.stateDir}' - ${cfg.user} ${cfg.group} - -"
103 ];
104
105 systemd.services.octoprint = {
106 description = "OctoPrint, web interface for 3D printers";
107 wantedBy = [ "multi-user.target" ];
108 after = [ "network.target" ];
109 path = [ pluginsEnv ];
110
111 preStart = ''
112 if [ -e "${cfg.stateDir}/config.yaml" ]; then
113 ${pkgs.yaml-merge}/bin/yaml-merge "${cfg.stateDir}/config.yaml" "${cfgUpdate}" > "${cfg.stateDir}/config.yaml.tmp"
114 mv "${cfg.stateDir}/config.yaml.tmp" "${cfg.stateDir}/config.yaml"
115 else
116 cp "${cfgUpdate}" "${cfg.stateDir}/config.yaml"
117 chmod 600 "${cfg.stateDir}/config.yaml"
118 fi
119 '';
120
121 serviceConfig = {
122 ExecStart = "${pluginsEnv}/bin/octoprint serve -b ${cfg.stateDir}";
123 User = cfg.user;
124 Group = cfg.group;
125 SupplementaryGroups = [
126 "dialout"
127 ];
128 };
129 };
130
131 };
132
133}