Duet3D Logo

    Duet3D

    • Register
    • Login
    • Search
    • Categories
    • Tags
    • Documentation
    • Order
    1. Home
    2. dainon
    • Profile
    • Following 0
    • Followers 0
    • Topics 3
    • Posts 8
    • Best 1
    • Controversial 0
    • Groups 0

    dainon

    @dainon

    I'm a software engineer by profession with an interest in making things. Things includes: Designs in Fusion360, Full-stack Web Development, 3D printing, CNC, Electronics, Adobe (Photoshop, Illustrator, Premiere), Cycling, and Bourbon.

    6
    Reputation
    1
    Profile views
    8
    Posts
    0
    Followers
    0
    Following
    Joined Last Online
    Website www.youtube.com/channel/UC9wHy-_3wiNEzPncfyVW45w Age 41

    dainon Unfollow Follow

    Best posts made by dainon

    • Readdressing the CNC Gui Thoughts

      Re: CNC Gui Thoughts

      I read the original CNC Gui Thoughts post and was late to the game. I'm reviving it with some of my thoughts, based on what I've done. I'd love to see more CNC specific features and customization down the road.

      I'm new to CNC with a background in 3D printing and software engineering. I write a lot of website control pages for my primary job, but not in Vue. Initially I planned on customizing the Duet UI from the open-source code; however, the learning curve for editing the Duet3D Web UI was higher than writing my own website, watching the REST and WS networking traffic, and replicating that. I created this WebUI in NodeJS/ReactJS, which I'm more comfortable with than Vue and other people's code.

      Here's some of the thoughts I've had with the Duet3D Web UI that inspired this:

      1. Movement buttons should disable when movement not allowed.
      2. Layout of the movement buttons puts a strain on my brain
      3. Less jumping around between UI pages
      4. Clearer workplace selections
      5. Less empty space (CSS margins/padding)
      6. Cellphone layout removes some movement options (5 to 3 buttons of movement)
      7. Lack of GCode Viewer based on current tool position in a CNC non FDM view
      • I see a lot of discussion about plugins, love to know where people get external plugins from

      For me, the most useful part of the custom UI is the layout of the movement buttons, clearer workspace coordinates, enabled/disabled buttons based on machine state, and having everything in one page that fits on my cellphone (STOP always available across the top). The layout is design consideration is cellphone first, then tablet, then computer.

      WebUI.png

      The image below is a collage of the UI. Several screenshots of the buttons where the machine position is different and the movement buttons are enabled/disabled based on limits. All information comes from the network traffic, which in-turn comes from the config files. This means there's no hard-coded limits based on my machine. And I wrote the Gcode viewer in ThreeJS, not my favorite thing to do, but I turned out nicely.

      Collage of features
      DainonDesigns-UI.png

      I'm still in the CNC building process, and have not cut anything, but have run it as a pen drawing CNC. Most of my UI redesign came from my inexperience with CNC and its learning curve. The primary lesson learned is CRAHSING the CNC by accidentally clicking on the wrong thing during the configuration/build phase of this process. I'm sure I'll understand some features down the road that I've currently misinterpreted and this UI will evolve.

      There's some cool (from a hack perspective) benefits to this design; I consider it a benefit at least. For starters, this is it's own website with a back-end and a front-end. It doesn't replace the Duet3D Web UI; instead, it enhances it. The hack is to use Nginx as a proxy redirect based on URL paths and interact with the REST/WS traffic that already exists. From what I can tell, there is CORS requirements to come from the same domain for some network commands; so, here's how this setup works in Nginx.

      Update: More specifics on how/why is covered over here: https://forum.duet3d.com/post/310830

      Web Server (reused one I already have, could use a RPi or really anything with linux)

      • Domain ($12 a year routed to your IP-Address)
      • Nginx (port-forward 80/443 from router to Web Server for proxy-redirect)
      • Custom CNC UI Website (REST/WS)

      SBC with Duet3 6HC

      • Standard Duet Web UI

      I don't know how many people really care about this, but I've learned a lot from user posts over the years that inspired my own projects, so I'm going all-in on posting this here.

      Nginx Server Config File (I've removed the Certbot https config portion as it's not relevant here, but add it to simplify the Chrome HTTPS experience)
      File: /etc/nginx/sites-enabled/cnc.DOMAIN-NAME

      server {
        server_name cnc.DOMAIN-NAME;
        access_log /var/log/nginx/cnc.DOMAIN-NAME.access.log main;
        listen 80;
      
        client_max_body_size 90M;
      
        allow 192.168.1.0/24; # allow your local subnet
        deny all;                          # prevent external access
      
        # route the Duet3D traffic to the SBC
        location / {
          proxy_pass http://SBC-IP-ADDRESS/;
          proxy_set_header Host $host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $http_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto $scheme;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection "upgrade";
          proxy_read_timeout 1d;
        }
      
        # Route 'server' path traffic to custom website (32222 is some random port I've chosen)
        location /server {
          proxy_pass http://localhost:32222/server;
          proxy_set_header Host $host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $http_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto $scheme;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection "upgrade";
          proxy_read_timeout 1d;
        }
      
        # route 'development' to my development computer's custom website
        location /development{
          proxy_pass http://DEVELOPMENT-IP:32222/development;
          proxy_set_header Host $host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $http_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto $scheme;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection "upgrade";
          proxy_read_timeout 1d;
        }
      
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
          root /usr/share/nginx/html;
        }
      }
      

      This configuration allows the following:

      • Routes to the main Duet3D website
        http://cnc.DOMAIN-NAME/
      • Routes to the custom website running on the server
        http://cnc.DOMAIN-NAME/server
      • Routes to the website running on my PC where I develop new features
        http://cnc.DOMAIN-NAME/development

      The website's index lives where the domain path root is. For anyone familiar with expressJS, that would look like this

      File server.ts

      ...
      import { router } from './routes/rest';
      app.use(`/${process.env.URI_PATH}`, router);
      ...
      

      Where process.env.URI_PATH comes from an environment variable file to use server or development depending on where it's running.

      File .env

      URI_PATH=server
      

      The networking to control the Duet takes a little click-n-watch of the network traffic and is too much to get into here. Let me know if this kind of 'hack' project is useful to anyone.

      If you've read this far, here's some more code for you. This is to relay some REST controls that have CORS domain requirements. The web socket is handled from the browser front-end to the Duet3D SBC as CORS isn't a thing.

      File: ./routes/rest.ts

      import express from 'express';
      export const router = express.Router();
      const https = require('https');
      
      router.get('/', (req, res) => {
        res.render('index');
      });
      
      router.get('/cnc/connect', (req, res) => {
        const server = https.get(
          'https://cnc.DOMAIN-NAME/machine/connect?password=reprap',
          (response) => {
            if (response.statusCode !== 200) {
              res.sendStatus(503);
              return;
            }
      
            res.sendStatus(200);
          },
        );
      });
      
      router.get('/cnc/settings', async (req, res) => {
        getDuet(
          'https://cnc.DOMAIN-NAME/machine/file/0%3A%2Fsys%2Fdwc-settings.json',
          res,
        );
      });
      
      router.get('/files/sys', (req, res) => {
        getDuet('https://cnc.DOMAIN-NAME/machine/directory/0%3A%2Fsys', res);
      });
      
      router.get('/files/macros', (req, res) => {
        getDuet('https://cnc.DOMAIN-NAME/machine/directory/0%3A%2Fmacros%2F', res);
      });
      
      router.get('/jobs', (req, res) => {
        getDuet('https://cnc.DOMAIN-NAME/machine/directory/0%3A%2Fgcodes%2F', res);
      });
      
      router.get('/file/:name', (req, res) => {
        let { name } = req.params;
        getDuetFile(
          `https://cnc.DOMAIN-NAME/machine/file/0%3A%2Fgcodes%2F${name}`,
          res,
        );
      });
      
      router.get('/cnc/move/:value', async (req, res) => {
        let { value } = req.params;
      
        let commands = ['M120', 'G91', `G1 ${value} F6000`, 'G90', 'M121'];
        let command = formatGcode(commands);
      
        console.log('/cnc/move/:value', command);
        const options = {
          hostname: 'cnc.DOMAIN-NAME',
          port: 443,
          path: '/machine/code?async=true',
          method: 'POST',
        };
        const request = https.request(options, (response) => {
          console.log('statusCode:', res.statusCode);
          console.log('headers:', res.headers);
      
          response.on('data', (d) => {
            process.stdout.write(d);
          });
        });
      
        request.write(command);
        request.end();
        res.sendStatus(200);
      });
      
      router.get('/cnc/stop', async (req, res) => {
        let { value } = req.params;
      
        let commands = ['M112', 'M999'];
        let command = formatGcode(commands);
      
        console.log('/cnc/stop', command);
        const options = {
          hostname: 'cnc.DOMAIN-NAME',
          port: 443,
          path: '/machine/code',
          method: 'POST',
        };
        const request = https.request(options, (response) => {
          console.log('statusCode:', res.statusCode);
          console.log('headers:', res.headers);
      
          response.on('data', (d) => {
            process.stdout.write(d);
          });
        });
      
        request.write(command);
        request.end();
        res.sendStatus(200);
      });
      
      router.post('/cnc/commands', async (req, res) => {
        let commands = req.body;
        let command = formatGcode(commands);
      
        console.log('/cnc/commands', command);
        const options = {
          hostname: 'cnc.DOMAIN-NAME',
          port: 443,
          path: '/machine/code',
          method: 'POST',
        };
        const request = https.request(options, (response) => {
          console.log('statusCode:', res.statusCode);
          console.log('headers:', res.headers);
      
          response.on('data', (d) => {
            process.stdout.write(d);
          });
        });
      
        request.write(command);
        request.end();
        res.sendStatus(200);
      });
      
      function formatGcode(commands) {
        return commands.join('\n');
      }
      
      function getDuet(url, res) {
        https.get(url, (response) => {
          if (response.statusCode !== 200) {
            res.sendStatus(503);
            return;
          }
      
          let data = '';
      
          response.on('data', (chunk) => {
            data += chunk;
          });
      
          response.on('close', () => {
            console.log('Retrieved all data');
            res.send(data);
          });
        });
      }
      
      function getDuetFile(url, res) {
        https.get(url, (response) => {
          if (response.statusCode !== 200) {
            res.sendStatus(503);
            return;
          }
      
          let data = '';
      
          response.on('data', (chunk) => {
            data += chunk;
          });
      
          response.on('close', () => {
            console.log('Retrieved all data');
            res.send({ contents: data });
          });
        });
      }
      
      posted in CNC
      dainon
      dainon

    Latest posts made by dainon

    • RE: Spindle Configuration & Setup Help

      Solved:
      I got the spindle working. Switched over from fan to heater, then to the 5V PWM VFD output, which is Out9 (pins: out9->pwm+, GND->pwm-). The spindle works now. Won't stop spinning when I give it an M5, but that's a problem for another day.

      Regarding the information out there and trying most of it, this solution is mentioned here:
      https://duet3d.dozuki.com/Wiki/Configuring_RepRapFirmware_for_a_CNC_machine
      Specifically the section: Connecting a spindle, option 2

      Here's the relevant config file section:

      M950 R0 C"out9" Q100 L24000
      M563 P0 R0 S"Spindle"
      G10 P0 X0 Y0 Z0
      G10 P0 R0 S0
      M568 P0 F0                     
      T0
      

      5V PWM* - Noted at the bottom, connected as Out9, but the 3 pins beside it.
      out9.PNG

      posted in CNC
      dainon
      dainon
    • Spindle Configuration & Setup Help

      I hooked up a PWM to voltage module following the Workbee CNC w/Duet and Chinese Spindle Control post over on OpenBuilds and a lot of reading over here. I didn't have luck following the Workbee spindle configuration. I'm not certain in that example which specific PWM pins are being used. I chose to use OUT 4 and finally got the configuration not to bark at me for the tool not being defined, etc. I connected a volt meter to the output of the PWM to Voltage Module and sent M3 S4000 or M3 S10000 and nothing happened.

      Would someone please take a look at my configuration file and setup? And possibly help me figure out what I'm missing. Everything else works with the CNC and I've been able to play around with it.

      Notes for the VFD; however, I'm testing with a volt meter so these are not yet relevant

      • P0001 = 1 // Source of Operations, 1 = Set by external controls
      • P0002 = 1 // Source of Operating Frequency, 1 = Set by external terminals
      • Jumper from DCM to FOR for always on mode
      • Jumper for VI/VR for pins 1&2 // When using external connection potentiometer

      Workbee CNC w/Duet and Chinese Spindle Control
      https://openbuilds.com/threads/workbee-cnc-w-duet2-and-chinese-spindle-control.14004/

      PWM to Voltage Module
      https://www.amazon.com/dp/B07XZ836QF?psc=1&ref=ppx_yo2ov_dt_b_product_details

      System Specifications
      Duet3D 6HC with SBC
      Duet Web Control 3.4.5
      Huanyang HY01D511B (with 1.5kW Spindle)

      Configuration File - Comments aren't always accurate as I'm still debugging things

      ; Configuration file for Duet 3 MB 6HC (firmware version 3.3)
      ; executed by the firmware on start-up
      ;
      ; generated by RepRapFirmware Configuration Tool v3.3.15 on Thu Feb 09 2023 09:08:43 GMT-0500 (Eastern Standard Time)
      
      ; Globals
      global xMax = 660;
      global yMax = 570;
      global zMax = 90;
      
      global speedMax = 5000;
      global zSpeedMax = 400;
      
      global motorCurrent = 2240;
      
      ; General preferences
      G90                            ; send absolute coordinates...
      M83                            ; ...but relative extruder moves
      M550 P"CNC"                    ; set printer name
      
      ; Network
      M586 P0 S1                     ; enable HTTP
      M586 P1 S0                     ; disable FTP
      M586 P2 S0                     ; disable Telnet
      
      ; Drives
      M569 P0.0 S0                   ; physical drive 0.0 goes forwards - X
      M569 P0.1 S0                   ; physical drive 0.1 goes forwards - Y1 - Left
      M569 P0.2 S0                   ; physical drive 0.2 goes forwards - Y2 - Right
      M569 P0.3 S1                   ; physical drive 0.3 goes forwards - Z
      M584 X0.0 Y0.1:0.2 Z0.3        ; set drive mapping
      M350 X16 Y16 Z16 I1            ; configure microstepping with interpolation
      M92 X640.1582 Y640.1582 Z1600.00   ; set steps per mm
      M566 X900.00 Y900.00 Z60.00    ; set maximum instantaneous speed changes (mm/min)
      M203 X{global.speedMax} Y{global.speedMax} Z{global.zSpeedMax} ; set maximum speeds (mm/min)
      M201 X500.00 Y500.00 Z80.00    ; set accelerations (mm/s^2) // The original speed
      M906 X{global.motorCurrent} Y{global.motorCurrent} Z{global.motorCurrent} I30     ; set motor currents (mA) and motor idle factor in per cent
      M84 S30                        ; Set idle timeout
      
      ; Axis Limits
      M208 X0 Y0 Z0 S1               ; set axis minima
      M208 X{global.xMax} Y{global.yMax} Z{global.zMax} S0          ; set axis maxima
      
      ; Endstops
      M574 X1 S1 P"!io0.in"          ; configure switch-type (e.g. microswitch) endstop for low end on X via pin ^io0.in
      M574 Y2 S1 P"!io1.in"          ; configure switch-type (e.g. microswitch) endstop for low end on Y via pin ^io1.in
      M574 Z2 S1 P"!io2.in"         ; configure switch-type (e.g. microswitch) endstop for low end on Z via pin ^io2.in
      
      ; Z-Probe
      M558 P0 H5 F120 T6000          ; disable Z probe but set dive height, probe speed and travel speed
      
      M453 ; CNC mode
      
      ; Tools
      M950 R0 C"out4" Q100 L0:14000
      M563 P0 R0 S"Spindle"
      G10 P0 X0 Y0 Z0
      G10 P0 R0 S0
      M568 P0 F0                     ; Set Spindle speed to 0
      T0
      
      M453 P0 R14000 F100
      

      Photos for Reference and Double Checking
      Duet3D_Wiring.png
      VFD.png
      IndyMill Build
      20230321_141021.jpg

      posted in CNC
      dainon
      dainon
    • RE: Summary of HuanYang VFD Control by Duet3D 6HC

      Thank you all. I bought a PWM to Analog converter and will be wiring that up today. I'll mark this topic solved.

      posted in CNC
      dainon
      dainon
    • RE: CORS policy: No 'Access-Control-Allow-Origin'

      @hauschka

      Can you tell me how exactly a reverse proxy circumvents the CORS issue?

      CORS, which is a security feature, is upheld by the browser to maintain that a client is requesting the resources from the same origin. In the case of writing your own website for Duet you now have 2 origins: (A) Duet3D Web Server, (B) Your Custom Web Server. Each of these is it's own origin. As a client using (B), you request pages/content from (B) which becomes B-Client in this example. Your code on the client side sends requests to from B-Client to A, which is Cross-Origin Resource Sharing (CORS). This CORS error is the default and both the client and server have to explicitly state 'no-cors' in their HTTP/HTTPS headers. When you disable CORS from the client request, you've found it doesn't work either. To me, this is more headache than it's worth even when you control all the code, because CORS pops-up when you think you've solved it For that last time! in an OPTIONS packet you didn't explicitly send (i.e., like a WS/WSS upgrade packet).

      Answer: Because, like you I was frustrated for many hours with CORS, I've shown two solutions to the same problem and not explained it very well. 1) The reverse-proxy makes it to where A and B are the same origin and your B-Client can talk to A and A doesn't know the difference. 2) If you cannot do this, you can relay the REST call from your server. For example: B-Client sends a REST call to B, then B sends a REST call to A, A responds to B, then B responds back to B-Client. This works because the CORs checks are enforced by the client browser, and the server side just says which origins are allowed (kind of stupid if you ask me, and you can test this using a API design tool like Postman or Insomnia). I just tested both Nginx and Server-side REST relay independently in my code to make sure I'm not blowing smoke, and I'm not.

      The thing is.... I'm not even sure what is causing the CORS, as I AM connecting to the device from the same location (ie origin) after reset.

      I'm trying to understand where the error stems from and how your implementation is different?

      When you say same location, what specifically are your referring to: IP-Address, domain name, sub-domain, etc?

      posted in Duet Web Control
      dainon
      dainon
    • RE: CORS policy: No 'Access-Control-Allow-Origin'

      @hauschka
      I ran into this issue while creating my own web interface for the Duet3 6HC.

      Instead of dealing with the headaches of CORS, which I've done for projects at work, I bypassed the CORS errors by using the same domain name, and relaying the REST calls on the server side. I wrote it up in the CNC forum if it's of any use to you. I have both REST and WS working this way with no issues.

      https://forum.duet3d.com/topic/31844/readdressing-the-cnc-gui-thoughts

      Basically use Nginx as the domain proxy redirect and the new website with different paths. As this is only an issue with REST, your WebSockets will work just fine as CORS doesn't apply to the WS/WSS protocol. I posted the nginx config and REST relay file over in CNC.

      posted in Duet Web Control
      dainon
      dainon
    • RE: Summary of HuanYang VFD Control by Duet3D 6HC

      @dc42 Thanks for that information. I've had similar issues with a hydroponic Ph sensor connected to the pumping system circuit. When the pump kicked off, the sensor got out of whack and need some time to settle. I assume what you are saying is similar that? I'm a hobbyist and not an expert in electrical circuits.

      posted in CNC
      dainon
      dainon
    • Readdressing the CNC Gui Thoughts

      Re: CNC Gui Thoughts

      I read the original CNC Gui Thoughts post and was late to the game. I'm reviving it with some of my thoughts, based on what I've done. I'd love to see more CNC specific features and customization down the road.

      I'm new to CNC with a background in 3D printing and software engineering. I write a lot of website control pages for my primary job, but not in Vue. Initially I planned on customizing the Duet UI from the open-source code; however, the learning curve for editing the Duet3D Web UI was higher than writing my own website, watching the REST and WS networking traffic, and replicating that. I created this WebUI in NodeJS/ReactJS, which I'm more comfortable with than Vue and other people's code.

      Here's some of the thoughts I've had with the Duet3D Web UI that inspired this:

      1. Movement buttons should disable when movement not allowed.
      2. Layout of the movement buttons puts a strain on my brain
      3. Less jumping around between UI pages
      4. Clearer workplace selections
      5. Less empty space (CSS margins/padding)
      6. Cellphone layout removes some movement options (5 to 3 buttons of movement)
      7. Lack of GCode Viewer based on current tool position in a CNC non FDM view
      • I see a lot of discussion about plugins, love to know where people get external plugins from

      For me, the most useful part of the custom UI is the layout of the movement buttons, clearer workspace coordinates, enabled/disabled buttons based on machine state, and having everything in one page that fits on my cellphone (STOP always available across the top). The layout is design consideration is cellphone first, then tablet, then computer.

      WebUI.png

      The image below is a collage of the UI. Several screenshots of the buttons where the machine position is different and the movement buttons are enabled/disabled based on limits. All information comes from the network traffic, which in-turn comes from the config files. This means there's no hard-coded limits based on my machine. And I wrote the Gcode viewer in ThreeJS, not my favorite thing to do, but I turned out nicely.

      Collage of features
      DainonDesigns-UI.png

      I'm still in the CNC building process, and have not cut anything, but have run it as a pen drawing CNC. Most of my UI redesign came from my inexperience with CNC and its learning curve. The primary lesson learned is CRAHSING the CNC by accidentally clicking on the wrong thing during the configuration/build phase of this process. I'm sure I'll understand some features down the road that I've currently misinterpreted and this UI will evolve.

      There's some cool (from a hack perspective) benefits to this design; I consider it a benefit at least. For starters, this is it's own website with a back-end and a front-end. It doesn't replace the Duet3D Web UI; instead, it enhances it. The hack is to use Nginx as a proxy redirect based on URL paths and interact with the REST/WS traffic that already exists. From what I can tell, there is CORS requirements to come from the same domain for some network commands; so, here's how this setup works in Nginx.

      Update: More specifics on how/why is covered over here: https://forum.duet3d.com/post/310830

      Web Server (reused one I already have, could use a RPi or really anything with linux)

      • Domain ($12 a year routed to your IP-Address)
      • Nginx (port-forward 80/443 from router to Web Server for proxy-redirect)
      • Custom CNC UI Website (REST/WS)

      SBC with Duet3 6HC

      • Standard Duet Web UI

      I don't know how many people really care about this, but I've learned a lot from user posts over the years that inspired my own projects, so I'm going all-in on posting this here.

      Nginx Server Config File (I've removed the Certbot https config portion as it's not relevant here, but add it to simplify the Chrome HTTPS experience)
      File: /etc/nginx/sites-enabled/cnc.DOMAIN-NAME

      server {
        server_name cnc.DOMAIN-NAME;
        access_log /var/log/nginx/cnc.DOMAIN-NAME.access.log main;
        listen 80;
      
        client_max_body_size 90M;
      
        allow 192.168.1.0/24; # allow your local subnet
        deny all;                          # prevent external access
      
        # route the Duet3D traffic to the SBC
        location / {
          proxy_pass http://SBC-IP-ADDRESS/;
          proxy_set_header Host $host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $http_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto $scheme;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection "upgrade";
          proxy_read_timeout 1d;
        }
      
        # Route 'server' path traffic to custom website (32222 is some random port I've chosen)
        location /server {
          proxy_pass http://localhost:32222/server;
          proxy_set_header Host $host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $http_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto $scheme;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection "upgrade";
          proxy_read_timeout 1d;
        }
      
        # route 'development' to my development computer's custom website
        location /development{
          proxy_pass http://DEVELOPMENT-IP:32222/development;
          proxy_set_header Host $host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $http_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto $scheme;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection "upgrade";
          proxy_read_timeout 1d;
        }
      
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
          root /usr/share/nginx/html;
        }
      }
      

      This configuration allows the following:

      • Routes to the main Duet3D website
        http://cnc.DOMAIN-NAME/
      • Routes to the custom website running on the server
        http://cnc.DOMAIN-NAME/server
      • Routes to the website running on my PC where I develop new features
        http://cnc.DOMAIN-NAME/development

      The website's index lives where the domain path root is. For anyone familiar with expressJS, that would look like this

      File server.ts

      ...
      import { router } from './routes/rest';
      app.use(`/${process.env.URI_PATH}`, router);
      ...
      

      Where process.env.URI_PATH comes from an environment variable file to use server or development depending on where it's running.

      File .env

      URI_PATH=server
      

      The networking to control the Duet takes a little click-n-watch of the network traffic and is too much to get into here. Let me know if this kind of 'hack' project is useful to anyone.

      If you've read this far, here's some more code for you. This is to relay some REST controls that have CORS domain requirements. The web socket is handled from the browser front-end to the Duet3D SBC as CORS isn't a thing.

      File: ./routes/rest.ts

      import express from 'express';
      export const router = express.Router();
      const https = require('https');
      
      router.get('/', (req, res) => {
        res.render('index');
      });
      
      router.get('/cnc/connect', (req, res) => {
        const server = https.get(
          'https://cnc.DOMAIN-NAME/machine/connect?password=reprap',
          (response) => {
            if (response.statusCode !== 200) {
              res.sendStatus(503);
              return;
            }
      
            res.sendStatus(200);
          },
        );
      });
      
      router.get('/cnc/settings', async (req, res) => {
        getDuet(
          'https://cnc.DOMAIN-NAME/machine/file/0%3A%2Fsys%2Fdwc-settings.json',
          res,
        );
      });
      
      router.get('/files/sys', (req, res) => {
        getDuet('https://cnc.DOMAIN-NAME/machine/directory/0%3A%2Fsys', res);
      });
      
      router.get('/files/macros', (req, res) => {
        getDuet('https://cnc.DOMAIN-NAME/machine/directory/0%3A%2Fmacros%2F', res);
      });
      
      router.get('/jobs', (req, res) => {
        getDuet('https://cnc.DOMAIN-NAME/machine/directory/0%3A%2Fgcodes%2F', res);
      });
      
      router.get('/file/:name', (req, res) => {
        let { name } = req.params;
        getDuetFile(
          `https://cnc.DOMAIN-NAME/machine/file/0%3A%2Fgcodes%2F${name}`,
          res,
        );
      });
      
      router.get('/cnc/move/:value', async (req, res) => {
        let { value } = req.params;
      
        let commands = ['M120', 'G91', `G1 ${value} F6000`, 'G90', 'M121'];
        let command = formatGcode(commands);
      
        console.log('/cnc/move/:value', command);
        const options = {
          hostname: 'cnc.DOMAIN-NAME',
          port: 443,
          path: '/machine/code?async=true',
          method: 'POST',
        };
        const request = https.request(options, (response) => {
          console.log('statusCode:', res.statusCode);
          console.log('headers:', res.headers);
      
          response.on('data', (d) => {
            process.stdout.write(d);
          });
        });
      
        request.write(command);
        request.end();
        res.sendStatus(200);
      });
      
      router.get('/cnc/stop', async (req, res) => {
        let { value } = req.params;
      
        let commands = ['M112', 'M999'];
        let command = formatGcode(commands);
      
        console.log('/cnc/stop', command);
        const options = {
          hostname: 'cnc.DOMAIN-NAME',
          port: 443,
          path: '/machine/code',
          method: 'POST',
        };
        const request = https.request(options, (response) => {
          console.log('statusCode:', res.statusCode);
          console.log('headers:', res.headers);
      
          response.on('data', (d) => {
            process.stdout.write(d);
          });
        });
      
        request.write(command);
        request.end();
        res.sendStatus(200);
      });
      
      router.post('/cnc/commands', async (req, res) => {
        let commands = req.body;
        let command = formatGcode(commands);
      
        console.log('/cnc/commands', command);
        const options = {
          hostname: 'cnc.DOMAIN-NAME',
          port: 443,
          path: '/machine/code',
          method: 'POST',
        };
        const request = https.request(options, (response) => {
          console.log('statusCode:', res.statusCode);
          console.log('headers:', res.headers);
      
          response.on('data', (d) => {
            process.stdout.write(d);
          });
        });
      
        request.write(command);
        request.end();
        res.sendStatus(200);
      });
      
      function formatGcode(commands) {
        return commands.join('\n');
      }
      
      function getDuet(url, res) {
        https.get(url, (response) => {
          if (response.statusCode !== 200) {
            res.sendStatus(503);
            return;
          }
      
          let data = '';
      
          response.on('data', (chunk) => {
            data += chunk;
          });
      
          response.on('close', () => {
            console.log('Retrieved all data');
            res.send(data);
          });
        });
      }
      
      function getDuetFile(url, res) {
        https.get(url, (response) => {
          if (response.statusCode !== 200) {
            res.sendStatus(503);
            return;
          }
      
          let data = '';
      
          response.on('data', (chunk) => {
            data += chunk;
          });
      
          response.on('close', () => {
            console.log('Retrieved all data');
            res.send({ contents: data });
          });
        });
      }
      
      posted in CNC
      dainon
      dainon
    • Summary of HuanYang VFD Control by Duet3D 6HC

      I've been reading many posts here and via other sources regarding VFD and Duet3D control. To summarize what I've read, most everyone uses an inexpensive PWM to 0-10V board to control the "Inexpensive" HuanYang VFD for speed control. Someone mentioned using the 5V PWM VFD support on the mainboard, but that's still PWM. The HuanYang uses 0-5 or 0-10V speed control not PWM. There's a discussion here about what more can be "built-in" to the Duet3D for CNC spindle improvements, but no clear direction or answer for my question today.

      What I'm curious of is if there's a way to configure, for example, the OUT_1 pins (out1, V_FUSED) for variable volts output to send the 0-10V control that the HuanYang VFD uses? I've connected a volt meter to see if this works, but I'm not certain of the config file parameters as I always get 0V. I've tried the following, but have also read I possibly need to disable a heater.

      ; Tools
      G10 P0 x0 Y0 Z0
      G10 P0 R0 S0
      M563 H0 S"Spindle"
      M950 S0 C"out1" R24000 Q100 T0
      

      I hope it goes without saying, this is confusing. I already have a friend who is short and snippy about what he thinks of my knowledge on the subject, so please be constructive here.

      Information About My System
      Custom Built CNC - Based on IndyMill
      Duet3D Mainboard 6HC with Raspberry PI
      Huanyang VFD HY01D511B (HY Series)

      posted in CNC
      dainon
      dainon