From 1db9c3c13e7e91707326d589cce40776493081a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joshua=20M=C3=B6ckelmann?= <111989400+JoshuaMoeckelmann@users.noreply.github.com> Date: Fri, 16 Aug 2024 09:16:39 +0200 Subject: [PATCH] Allow selecting rendering date/time --- README.md | 4 +- doc/options.png | Bin 17776 -> 18271 bytes .../ApplicationPlugin.properties | 2 + .../HomeAssistantFloorPlan/Controller.java | 15 +- .../HomeAssistantFloorPlan/Panel.java | 133 +++++++++++------- .../HomeAssistantFloorPlan/Settings.java | 14 +- .../SimpleDocumentListener.java | 24 ++++ 7 files changed, 137 insertions(+), 55 deletions(-) create mode 100644 src/com/shmuelzon/HomeAssistantFloorPlan/SimpleDocumentListener.java diff --git a/README.md b/README.md index c2b9039..24f8255 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,8 @@ the room they're located in. Please verify the list matches your expectations. Only relevant for "room overlay" light mixing mode * Renderer - Select which rendering engine to use, YafaRay or SunFlow * Quality - Choose the rendering quality (low or high) +* Render Time - The date and time of the rendered image, affects the sun + position * Output directory - The location on your PC where the floor plan images and YAML will be saved @@ -178,7 +180,7 @@ When using the "Room overlay" light mixing mode, it's also suggested to: ## Possible Future Enhancements - [x] Allow selecting renderer (SunFlow/Yafaray) - [x] Allow selecting quality (high/low) -- [ ] Allow selecting date/time of render +- [x] Allow selecting date/time of render - [ ] Create multiple renders for multiple hours of the day and display in Home Assistant according to local time - [x] Allow stopping rendering thread diff --git a/doc/options.png b/doc/options.png index 1e0d959fde84a849feb07e157636281bf520bc53..1ed8d81b9f2962a30d3af6c210547f6cb9219a50 100644 GIT binary patch literal 18271 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 IbxsLQ0Q1$a_62>2I=f&?DfLi=U_{)4ku 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 diff --git a/src/com/shmuelzon/HomeAssistantFloorPlan/ApplicationPlugin.properties b/src/com/shmuelzon/HomeAssistantFloorPlan/ApplicationPlugin.properties index 55e5eb2..2688a02 100644 --- a/src/com/shmuelzon/HomeAssistantFloorPlan/ApplicationPlugin.properties +++ b/src/com/shmuelzon/HomeAssistantFloorPlan/ApplicationPlugin.properties @@ -36,6 +36,8 @@ HomeAssistantFloorPlan.Panel.qualityLabel.text=Quality: HomeAssistantFloorPlan.Panel.qualityComboBox.LOW.text=Low HomeAssistantFloorPlan.Panel.qualityComboBox.HIGH.text=High +HomeAssistantFloorPlan.Panel.renderTimeLabel.text=Render time: + HomeAssistantFloorPlan.Panel.outputDirectoryLabel.text=Output directory: HomeAssistantFloorPlan.Panel.outputDirectory.title=Choose floor-plan output directory HomeAssistantFloorPlan.Panel.browseButton.text=Browse... diff --git a/src/com/shmuelzon/HomeAssistantFloorPlan/Controller.java b/src/com/shmuelzon/HomeAssistantFloorPlan/Controller.java index bbe41cb..392474a 100644 --- a/src/com/shmuelzon/HomeAssistantFloorPlan/Controller.java +++ b/src/com/shmuelzon/HomeAssistantFloorPlan/Controller.java @@ -46,6 +46,7 @@ public enum Quality {HIGH, LOW} private static final String CONTROLLER_SENSITIVTY = "sensitivity"; private static final String CONTROLLER_RENDERER = "renderer"; private static final String CONTROLLER_QUALITY = "quality"; + private static final String CONTROLLER_RENDER_TIME = "renderTime"; private static final String CONTROLLER_OUTPUT_DIRECTORY_NAME = "outputDirectoryName"; private static final String CONTROLLER_USE_EXISTING_RENDERS = "useExistingRenders"; @@ -68,6 +69,7 @@ public enum Quality {HIGH, LOW} private int sensitivity; private Renderer renderer; private Quality quality; + private long renderDateTime; private String outputDirectoryName; private String outputRendersDirectoryName; private String outputFloorplanDirectoryName; @@ -92,8 +94,8 @@ public StateIcon(String name, Point2d position, String type, String action, Stri public Controller(Home home) { this.home = home; settings = new Settings(home); - loadDefaultSettings(); camera = home.getCamera().clone(); + loadDefaultSettings(); propertyChangeSupport = new PropertyChangeSupport(this); lights = getEnabledLights(); lightsGroups = getLightsGroups(lights); @@ -109,6 +111,7 @@ public void loadDefaultSettings() { sensitivity = settings.getInteger(CONTROLLER_SENSITIVTY, 10); renderer = Renderer.valueOf(settings.get(CONTROLLER_RENDERER, Renderer.YAFARAY.name())); quality = Quality.valueOf(settings.get(CONTROLLER_QUALITY, Quality.HIGH.name())); + renderDateTime = settings.getLong(CONTROLLER_RENDER_TIME, camera.getTime()); outputDirectoryName = settings.get(CONTROLLER_OUTPUT_DIRECTORY_NAME, System.getProperty("user.home")); outputRendersDirectoryName = outputDirectoryName + File.separator + "renders"; outputFloorplanDirectoryName = outputDirectoryName + File.separator + "floorplan"; @@ -213,6 +216,15 @@ public void setQuality(Quality quality) { settings.set(CONTROLLER_QUALITY, quality.name()); } + public long getRenderDateTime() { + return renderDateTime; + } + + public void setRenderDateTime(long renderDateTime) { + this.renderDateTime = renderDateTime; + settings.setLong(CONTROLLER_RENDER_TIME, renderDateTime); + } + public void stop() { if (photoRenderer != null) { photoRenderer.stop(); @@ -231,6 +243,7 @@ public void render() throws IOException, InterruptedException { try { new File(outputRendersDirectoryName).mkdirs(); new File(outputFloorplanDirectoryName).mkdirs(); + camera.setTime(renderDateTime); build3dProjection(); String yaml = generateBaseRender(); diff --git a/src/com/shmuelzon/HomeAssistantFloorPlan/Panel.java b/src/com/shmuelzon/HomeAssistantFloorPlan/Panel.java index 35b0b1e..2a953cf 100644 --- a/src/com/shmuelzon/HomeAssistantFloorPlan/Panel.java +++ b/src/com/shmuelzon/HomeAssistantFloorPlan/Panel.java @@ -15,10 +15,12 @@ import java.awt.event.WindowEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.Date; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.ResourceBundle; +import java.util.TimeZone; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -37,14 +39,15 @@ import javax.swing.JSpinner; import javax.swing.JTextField; import javax.swing.JTree; +import javax.swing.SpinnerDateModel; import javax.swing.SpinnerNumberModel; import javax.swing.SwingUtilities; import javax.swing.border.LineBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; import javax.swing.plaf.basic.BasicTreeUI; +import javax.swing.text.DateFormatter; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeCellRenderer; @@ -85,6 +88,8 @@ private enum ActionType {BROWSE, START, STOP, CLOSE} private JComboBox qualityComboBox; private JLabel outputDirectoryLabel; private JTextField outputDirectoryTextField; + private JLabel renderTimeLabel; + private JSpinner renderTimeSpinner; private JButton outputDirectoryBrowseButton; private FileContentManager outputDirectoryChooser; private JCheckBox useExistingRendersCheckbox; @@ -274,27 +279,23 @@ public void actionPerformed(ActionEvent ev) { } }); - outputDirectoryLabel = new JLabel(); - outputDirectoryLabel.setText(resource.getString("HomeAssistantFloorPlan.Panel.outputDirectoryLabel.text")); - outputDirectoryTextField = new JTextField(); - outputDirectoryTextField.setText(controller.getOutputDirectory()); - outputDirectoryTextField.getDocument().addDocumentListener(new DocumentListener() { - public void insertUpdate(DocumentEvent e) { - startButton.setEnabled(!outputDirectoryTextField.getText().isEmpty()); - controller.setOutputDirectory(outputDirectoryTextField.getText()); - } - public void removeUpdate(DocumentEvent e) { - startButton.setEnabled(!outputDirectoryTextField.getText().isEmpty()); - controller.setOutputDirectory(outputDirectoryTextField.getText()); - } - public void changedUpdate(DocumentEvent e) { - startButton.setEnabled(!outputDirectoryTextField.getText().isEmpty()); - controller.setOutputDirectory(outputDirectoryTextField.getText()); + renderTimeLabel = new JLabel(); + renderTimeLabel.setText(resource.getString("HomeAssistantFloorPlan.Panel.renderTimeLabel.text")); + final SpinnerDateModel model = new SpinnerDateModel(); + renderTimeSpinner = new JSpinner(model); + final JSpinner.DateEditor editor = new JSpinner.DateEditor(renderTimeSpinner); + editor.getFormat().setTimeZone(TimeZone.getTimeZone("UTC")); + editor.getFormat().applyPattern("HH:mm dd/MM/yyyy"); + renderTimeSpinner.setEditor(editor); + final DateFormatter formatter = (DateFormatter)editor.getTextField().getFormatter(); + formatter.setAllowsInvalid(false); + formatter.setOverwriteMode(true); + model.setValue(new Date(controller.getRenderDateTime())); + renderTimeSpinner.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent ev) { + controller.setRenderDateTime(((Date) renderTimeSpinner.getValue()).getTime()); } }); - outputDirectoryBrowseButton = new JButton(actionMap.get(ActionType.BROWSE)); - outputDirectoryBrowseButton.setText(resource.getString("HomeAssistantFloorPlan.Panel.browseButton.text")); - outputDirectoryChooser = new FileContentManager(preferences); useExistingRendersCheckbox = new JCheckBox(); useExistingRendersCheckbox.setText(resource.getString("HomeAssistantFloorPlan.Panel.useExistingRenders.text")); @@ -302,10 +303,25 @@ public void changedUpdate(DocumentEvent e) { useExistingRendersCheckbox.setSelected(controller.getUserExistingRenders()); useExistingRendersCheckbox.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent ev) { - controller.setUserExistingRenders(useExistingRendersCheckbox.isSelected()); + controller.setUserExistingRenders(useExistingRendersCheckbox.isSelected()); } }); + outputDirectoryLabel = new JLabel(); + outputDirectoryLabel.setText(resource.getString("HomeAssistantFloorPlan.Panel.outputDirectoryLabel.text")); + outputDirectoryTextField = new JTextField(); + outputDirectoryTextField.setText(controller.getOutputDirectory()); + outputDirectoryTextField.getDocument().addDocumentListener(new SimpleDocumentListener() { + @Override + public void executeUpdate(DocumentEvent e) { + startButton.setEnabled(!outputDirectoryTextField.getText().isEmpty()); + controller.setOutputDirectory(outputDirectoryTextField.getText()); + } + }); + outputDirectoryBrowseButton = new JButton(actionMap.get(ActionType.BROWSE)); + outputDirectoryBrowseButton.setText(resource.getString("HomeAssistantFloorPlan.Panel.browseButton.text")); + outputDirectoryChooser = new FileContentManager(preferences); + progressBar = new JProgressBar() { @Override public String getString() { @@ -357,80 +373,97 @@ private void layoutComponents() { int labelAlignment = OperatingSystem.isMacOSX() ? JLabel.TRAILING : JLabel.LEADING; int standardGap = Math.round(2 * SwingTools.getResolutionScale()); Insets insets = new Insets(0, standardGap, 0, standardGap); + int currentGridYIndex = 0; - /* First row (Detected lights caption) */ + /* Detected lights caption */ add(detectedLightsLabel, new GridBagConstraints( - 0, 0, 1, 1, 0, 0, GridBagConstraints.CENTER, + 0, currentGridYIndex, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insets, 0, 0)); + currentGridYIndex++; - /* Second row (Detected lights tree) */ + /* Detected lights tree */ add(detectedLightsTree, new GridBagConstraints( - 0, 1, 4, 1, 0, 0, GridBagConstraints.CENTER, + 0, currentGridYIndex, 4, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insets, 0, 0)); + currentGridYIndex++; - /* Third row (Resolution) */ + /* Resolution */ add(widthLabel, new GridBagConstraints( - 0, 2, 1, 1, 0, 0, GridBagConstraints.CENTER, + 0, currentGridYIndex, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insets, 0, 0)); widthLabel.setHorizontalAlignment(labelAlignment); add(widthSpinner, new GridBagConstraints( - 1, 2, 1, 1, 0, 0, GridBagConstraints.LINE_START, + 1, currentGridYIndex, 1, 1, 0, 0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, insets, 0, 0)); add(heightLabel, new GridBagConstraints( - 2, 2, 1, 1, 0, 0, GridBagConstraints.CENTER, + 2, currentGridYIndex, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insets, 0, 0)); heightLabel.setHorizontalAlignment(labelAlignment); add(heightSpinner, new GridBagConstraints( - 3, 2, 1, 1, 0, 0, GridBagConstraints.LINE_START, + 3, currentGridYIndex, 1, 1, 0, 0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, insets, 0, 0)); + currentGridYIndex++; - /* Fourth row (Light mixing mode and sensitivity) */ + /* Light mixing mode and sensitivity */ add(lightMixingModeLabel, new GridBagConstraints( - 0, 3, 1, 1, 0, 0, GridBagConstraints.CENTER, + 0, currentGridYIndex, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insets, 0, 0)); add(lightMixingModeComboBox, new GridBagConstraints( - 1, 3, 1, 1, 0, 0, GridBagConstraints.CENTER, + 1, currentGridYIndex, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insets, 0, 0)); add(sensitivityLabel, new GridBagConstraints( - 2, 3, 1, 1, 0, 0, GridBagConstraints.CENTER, + 2, currentGridYIndex, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insets, 0, 0)); add(sensitivitySpinner, new GridBagConstraints( - 3, 3, 1, 1, 0, 0, GridBagConstraints.CENTER, + 3, currentGridYIndex, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insets, 0, 0)); + currentGridYIndex++; - /* Fifth row (Renderer + Quality) */ + /* Renderer + Quality */ add(rendererLabel, new GridBagConstraints( - 0, 4, 1, 1, 0, 0, GridBagConstraints.CENTER, + 0, currentGridYIndex, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insets, 0, 0)); add(rendererComboBox, new GridBagConstraints( - 1, 4, 1, 1, 0, 0, GridBagConstraints.CENTER, + 1, currentGridYIndex, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insets, 0, 0)); add(qualityLabel, new GridBagConstraints( - 2, 4, 1, 1, 0, 0, GridBagConstraints.CENTER, + 2, currentGridYIndex, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insets, 0, 0)); add(qualityComboBox, new GridBagConstraints( - 3, 4, 1, 1, 0, 0, GridBagConstraints.CENTER, + 3, currentGridYIndex, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insets, 0, 0)); - - /* Sixth row (Output directory) */ + currentGridYIndex++; + + /* Time selection */ + add(renderTimeLabel, new GridBagConstraints( + 0, currentGridYIndex, 1, 1, 0, 0, GridBagConstraints.CENTER, + GridBagConstraints.HORIZONTAL, insets, 0, 0)); + add(renderTimeSpinner, new GridBagConstraints( + 1, currentGridYIndex, 3, 1, 0, 0, GridBagConstraints.CENTER, + GridBagConstraints.HORIZONTAL, insets, 0, 0)); + currentGridYIndex++; + + /* Output directory */ add(outputDirectoryLabel, new GridBagConstraints( - 0, 5, 1, 1, 0, 0, GridBagConstraints.CENTER, + 0, currentGridYIndex, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insets, 0, 0)); add(outputDirectoryTextField, new GridBagConstraints( - 1, 5, 2, 1, 0, 0, GridBagConstraints.CENTER, + 1, currentGridYIndex, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insets, 0, 0)); add(outputDirectoryBrowseButton, new GridBagConstraints( - 3, 5, 1, 1, 0, 0, GridBagConstraints.CENTER, + 3, currentGridYIndex, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insets, 0, 0)); + currentGridYIndex++; - /* Seventh row (Options) */ + /* Options */ add(useExistingRendersCheckbox, new GridBagConstraints( - 0, 6, 2, 1, 0, 0, GridBagConstraints.CENTER, + 0, currentGridYIndex, 2, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insets, 0, 0)); + currentGridYIndex++; - /* Eighth row (progress bar) */ + /* Progress bar */ add(progressBar, new GridBagConstraints( - 0, 7, 4, 1, 0, 0, GridBagConstraints.CENTER, + 0, currentGridYIndex, 4, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, insets, 0, 0)); } @@ -443,7 +476,7 @@ public void displayView(View parentView) { if (currentPanel == this) { SwingUtilities.getWindowAncestor(Panel.this).toFront(); return; - } + } if (currentPanel != null) currentPanel.close(); final JOptionPane optionPane = new JOptionPane(this, diff --git a/src/com/shmuelzon/HomeAssistantFloorPlan/Settings.java b/src/com/shmuelzon/HomeAssistantFloorPlan/Settings.java index 2f1dfa3..67e8db5 100644 --- a/src/com/shmuelzon/HomeAssistantFloorPlan/Settings.java +++ b/src/com/shmuelzon/HomeAssistantFloorPlan/Settings.java @@ -17,11 +17,11 @@ public String get(String name, String defaultValue) { return defaultValue; return value; } - + public String get(String name) { return get(name, null); } - + public boolean getBoolean(String name, boolean defaultValue) { return Boolean.valueOf(get(name, String.valueOf(defaultValue))); } @@ -30,9 +30,13 @@ public int getInteger(String name, int defaultValue) { return Integer.valueOf(get(name, String.valueOf(defaultValue))); } + public long getLong(String name, long defaultValue) { + return Long.parseLong(get(name, String.valueOf(defaultValue))); + } + public void set(String name, String value) { String oldValue = get(PROPERTY_PREFIX + name); - + if (oldValue == value) return; home.setProperty(PROPERTY_PREFIX + name, value); @@ -46,4 +50,8 @@ public void setBoolean(String name, boolean value) { public void setInteger(String name, int value) { set(name, String.valueOf(value)); } + + public void setLong(String name, long value) { + set(name, String.valueOf(value)); + } }; diff --git a/src/com/shmuelzon/HomeAssistantFloorPlan/SimpleDocumentListener.java b/src/com/shmuelzon/HomeAssistantFloorPlan/SimpleDocumentListener.java new file mode 100644 index 0000000..559b04e --- /dev/null +++ b/src/com/shmuelzon/HomeAssistantFloorPlan/SimpleDocumentListener.java @@ -0,0 +1,24 @@ +package com.shmuelzon.HomeAssistantFloorPlan; + +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + +public abstract class SimpleDocumentListener implements DocumentListener { + + abstract void executeUpdate(DocumentEvent event); + + @Override + public void insertUpdate(DocumentEvent e) { + executeUpdate(e); + } + + @Override + public void removeUpdate(DocumentEvent e) { + executeUpdate(e); + } + + @Override + public void changedUpdate(DocumentEvent e) { + executeUpdate(e); + } +}