diff --git a/app/controllers/modals_controller.rb b/app/controllers/modals_controller.rb
index 7cdfe77..7ccb852 100644
--- a/app/controllers/modals_controller.rb
+++ b/app/controllers/modals_controller.rb
@@ -1,6 +1,6 @@
class ModalsController < ApplicationController
def open
@schedule = Schedule.new
- render partial: "partials/modals_open", locals: { type: params[:type], close_button: params[:close_button] }
+ render partial: "partials/modals_open", locals: { type: params[:type], id: params[:id], close_button: params[:close_button] }
end
end
diff --git a/app/controllers/modbus_controller.rb b/app/controllers/modbus_controller.rb
index fb3f7a7..a943e5d 100644
--- a/app/controllers/modbus_controller.rb
+++ b/app/controllers/modbus_controller.rb
@@ -1,11 +1,2 @@
class ModbusController < ApplicationController
- def start
- Modbus::PollingService.start
- redirect_to schedules_path
- end
-
- def stop
- Modbus::PollingService.stop
- redirect_to schedules_path
- end
end
diff --git a/app/controllers/schedules_controller.rb b/app/controllers/schedules_controller.rb
index 4390cb1..db55185 100644
--- a/app/controllers/schedules_controller.rb
+++ b/app/controllers/schedules_controller.rb
@@ -1,7 +1,11 @@
class SchedulesController < ApplicationController
def index
- @schedule = Schedule.order(:hour, :minute)
- @modbus_running = Modbus::PollingService.running?
+ @controllers = Controller.all
+ end
+
+ def view
+ @controller = Controller.find(params[:id])
+ @schedule = Schedule.where(controller_id: params[:id]).order(:hour, :minute)
end
def new
@@ -12,10 +16,10 @@ class SchedulesController < ApplicationController
@schedule = Schedule.new(schedule_params)
if @schedule.save
- redirect_to schedule_edit_schedules_path, notice: "스케쥴이 추가 되었습니다."
+ redirect_to schedule_edit_schedule_path(@schedule.controller_id), notice: "스케쥴이 추가 되었습니다."
else
error_messages = @schedule.errors.full_messages.join(", ")
- redirect_to schedule_edit_schedules_path, alert: "스케쥴 추가 실패: #{error_messages}"
+ redirect_to schedule_edit_schedule_path(@schedule.controller_id), alert: "스케쥴 추가 실패: #{error_messages}"
end
end
@@ -23,23 +27,23 @@ class SchedulesController < ApplicationController
@schedule = Schedule.find_by(id: params[:id])
if @schedule.destroy
- redirect_to schedule_edit_schedules_path, notice: "스케줄이 삭제되었습니다."
+ redirect_to schedule_edit_schedule_path(@schedule.controller_id), notice: "스케줄이 삭제되었습니다."
else
error_messages = @schedule.errors.full_messages.join(", ")
- redirect_to schedule_edit_schedules_path, alert: "스케쥴 삭제 실패: #{error_messages}"
+ redirect_to schedule_edit_schedule_path(@schedule.controller_id), alert: "스케쥴 삭제 실패: #{error_messages}"
end
end
def reset
- Schedule.delete_all
+ Schedule.where(controller_id: params[:id]).destroy_all
ActiveRecord::Base.connection.execute("DELETE FROM sqlite_sequence WHERE name='schedules'")
- Rails.application.load_seed
- redirect_to schedules_path, notice: "스케줄이 초기화되었습니다."
+ redirect_to schedule_edit_schedule_path(params[:id]), notice: "스케줄이 초기화되었습니다."
end
def schedule_edit
- @schedule = Schedule.order(:hour, :minute)
+ @controller = Controller.find(params[:id])
+ @schedule = Schedule.where(controller_id: params[:id]).order(:hour, :minute)
end
def schedule_edit_update
@@ -63,14 +67,14 @@ class SchedulesController < ApplicationController
end
if error_messages.any?
- redirect_to schedules_path, alert: error_messages.join("
")
+ redirect_to schedule_edit_schedule_path(params[:controller_id]), alert: error_messages.join("
")
else
- redirect_to schedules_path, notice: "스케줄이 성공적으로 업데이트되었습니다."
+ redirect_to schedule_edit_schedule_path(params[:controller_id]), notice: "스케줄이 성공적으로 업데이트되었습니다."
end
end
private
def schedule_params
- params.require(:schedule).permit(:hour, :minute, :is_active, :temperature)
+ params.require(:schedule).permit(:controller_id, :hour, :minute, :is_active, :temperature)
end
end
diff --git a/app/models/controller.rb b/app/models/controller.rb
new file mode 100644
index 0000000..3d0f332
--- /dev/null
+++ b/app/models/controller.rb
@@ -0,0 +1,3 @@
+class Controller < ApplicationRecord
+ has_many :schedules
+end
diff --git a/app/models/schedule.rb b/app/models/schedule.rb
index b8d23ca..1c1d7fd 100644
--- a/app/models/schedule.rb
+++ b/app/models/schedule.rb
@@ -1,9 +1,11 @@
class Schedule < ApplicationRecord
+ belongs_to :controller
+
validates :hour, presence: { message: "시간을 입력하세요" }
validates :minute, presence: { message: "분을 입력하세요" }
validates :temperature,
presence: { message: "온도를 입력하세요" },
numericality: { message: "온도는 숫자여야 합니다" },
format: { with: /\A\d+(\.\d)?\z/, message: "온도는 소수점 한 자리까지 입력 가능합니다" }
- validates :minute, uniqueness: { scope: :hour, message: "같은 시:분의 스케쥴이 이미 존재합니다" }
+ validates :minute, uniqueness: { scope: [ :controller_id, :hour ], message: "같은 시:분의 스케쥴이 이미 존재합니다" }
end
diff --git a/app/services/modbus/polling_service.rb b/app/services/modbus/polling_service.rb
index b981e70..6a3d7db 100644
--- a/app/services/modbus/polling_service.rb
+++ b/app/services/modbus/polling_service.rb
@@ -14,47 +14,34 @@ module Modbus
now = Time.now
current_time = format("%02d:%02d", now.hour, now.min)
puts "# current time: #{current_time}.#{now.sec}"
- schedule = Schedule.find_by(hour: now.hour, minute: now.min)
- apply_schedule(schedule) if schedule
+ schedules = Schedule.where(hour: now.hour, minute: now.min)
+ schedules.each { |schedule| apply_schedule(schedule) }
end
end
- def stop
- if defined?(@scheduler)
- @scheduler.shutdown(:kill)
- @scheduler = nil
- puts "[#{Time.now}] Modbus polling service 중지됨"
- else
- puts "[#{Time.now}] Scheduler 인스턴스 없음"
- end
- end
-
- def running?
- @scheduler
- end
-
private
def apply_schedule(schedule)
if schedule.is_active
- run_script("on_off.rb", "0", "[Schedule] ON")
+ run_script("on_off.rb", "#{schedule.controller.station_id}", "0", "[Schedule] #{schedule.controller.name} ON")
sleep 2
run_script(
"serial.rb",
+ "#{schedule.controller.station_id}",
(schedule.temperature * 10).to_i.to_s,
- "[Schedule] #{format('%02d:%02d', schedule.hour, schedule.minute)} → #{schedule.temperature}°C"
+ "[Schedule] #{schedule.controller.name} #{format('%02d:%02d', schedule.hour, schedule.minute)} → #{schedule.temperature}°C"
)
else
- run_script("on_off.rb", "1", "[Schedule] OFF")
+ run_script("on_off.rb", "#{schedule.controller.station_id}", "1", "[Schedule] #{schedule.controller.name} OFF")
end
end
- def run_script(file, arg, success_msg)
+ def run_script(file, controller_id, value, success_msg)
path = Rails.root.join(file)
- if system("ruby", path.to_s, arg)
+ if system("ruby", path.to_s, controller_id, value)
puts success_msg
Rails.logger.info success_msg
else
- error_message = "[#{Time.now}] #{file} 실행 실패 (args: #{arg})"
+ error_message = "[#{Time.now}] #{file} 실행 실패 (station_id: #{controller_id}, value: #{value})"
puts error_message
Rails.logger.error error_message
end
diff --git a/app/views/partials/modals/_add_schedule.html.erb b/app/views/partials/modals/_add_schedule.html.erb
index 7e7b284..db25ecd 100644
--- a/app/views/partials/modals/_add_schedule.html.erb
+++ b/app/views/partials/modals/_add_schedule.html.erb
@@ -1,5 +1,7 @@
<%= form_with model: @schedule, method: :post, data: { turbo: false }, class: 'flex flex-col h-full divide-y divide-border-table-border' do |form| %>
+ <%= form.hidden_field :controller_id, value: params[:id] %>
+
<%= Controller.find(params[:id]).name %> 컨트롤러
diff --git a/app/views/schedules/index.html.erb b/app/views/schedules/index.html.erb
index 444599f..748fa05 100644
--- a/app/views/schedules/index.html.erb
+++ b/app/views/schedules/index.html.erb
@@ -1,42 +1,7 @@
-
-
-
-
-
- | 시간 |
- 분 |
- 사용여부 |
- 온도 |
-
-
-
- <% @schedule.each do |s| %>
-
- | <%= s.hour %>시 |
- <%= s.minute %>분 |
- <%= s.is_active %> |
- <%= s.temperature %> °C |
-
- <% end %>
-
-
-
-
- <%= button_to "스케쥴러 시작", start_modbus_index_path, method: :post, class: "btn bg-accept" %>
- <%= button_to "스케쥴러 정지", stop_modbus_index_path, method: :post, class: "btn bg-danger" %>
-
-
-
- 스케쥴러 상태:
- <% if @modbus_running %>
- 실행 중
- <% else %>
- 정지됨
- <% end %>
-
-
-
-
- <%= link_to "수정", schedule_edit_schedules_path, class: "btn bg-default-slate" %>
+
+
+ <% @controllers.each do |c| %>
+ <%= link_to c.name, view_schedule_path(c.id), class: "btn bg-primary" %>
+ <% end %>
diff --git a/app/views/schedules/schedule_edit.html.erb b/app/views/schedules/schedule_edit.html.erb
index 8aebd07..abbf621 100644
--- a/app/views/schedules/schedule_edit.html.erb
+++ b/app/views/schedules/schedule_edit.html.erb
@@ -1,5 +1,7 @@
<%= form_with url: schedule_edit_update_schedules_path, method: :post, class: 'flex flex-col h-full divide-y divide-border-table-border' do %>
+ <%= hidden_field_tag :controller_id, params[:id] %>
+
<%= @controller.name %> 컨트롤러
@@ -40,13 +42,13 @@
<% end %>
- <%= button_to "초기화", reset_schedules_path,
+ <%= button_to "초기화", reset_schedule_path(params[:id]),
method: :post,
data: { turbo_confirm: "정말 초기화하시겠습니까? 모든 스케줄 데이터가 삭제됩니다." },
class: "btn bg-danger" %>
- <%= button_to "추가하기", open_modals_path(type: "add_schedule"),
+ <%= button_to "추가하기", open_modals_path(type: "add_schedule", id: params[:id]),
class: "btn bg-default-slate",
data: {
turbo_method: :post,
diff --git a/app/views/schedules/view.html.erb b/app/views/schedules/view.html.erb
new file mode 100644
index 0000000..65675a8
--- /dev/null
+++ b/app/views/schedules/view.html.erb
@@ -0,0 +1,28 @@
+
+
+
<%= @controller.name %> 컨트롤러
+
+
+
+ | 시간 |
+ 분 |
+ 사용여부 |
+ 온도 |
+
+
+
+ <% @schedule.each do |s| %>
+
+ | <%= s.hour %>시 |
+ <%= s.minute %>분 |
+ <%= s.is_active %> |
+ <%= s.temperature %> °C |
+
+ <% end %>
+
+
+
+
+ <%= link_to "수정", schedule_edit_schedule_path(@controller.id), class: "btn bg-default-slate" %>
+
+
diff --git a/config/routes.rb b/config/routes.rb
index 1df9955..dcc1dfd 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -14,17 +14,13 @@ Rails.application.routes.draw do
root "schedules#index"
resources :schedules do
- collection do
- post "reset"
+ member do
+ get "view"
get "schedule_edit"
- post "schedule_edit_update"
+ post "reset"
end
- end
-
- resources :modbus do
collection do
- post "start"
- post "stop"
+ post "schedule_edit_update"
end
end
diff --git a/db/migrate/20250416131430_create_controllers.rb b/db/migrate/20250416131430_create_controllers.rb
new file mode 100644
index 0000000..fe8652a
--- /dev/null
+++ b/db/migrate/20250416131430_create_controllers.rb
@@ -0,0 +1,10 @@
+class CreateControllers < ActiveRecord::Migration[8.0]
+ def change
+ create_table :controllers do |t|
+ t.string :name
+ t.integer :station_id
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/migrate/20250416131440_create_schedules.rb b/db/migrate/20250416131440_create_schedules.rb
index 51df18e..97b1285 100644
--- a/db/migrate/20250416131440_create_schedules.rb
+++ b/db/migrate/20250416131440_create_schedules.rb
@@ -1,6 +1,7 @@
class CreateSchedules < ActiveRecord::Migration[8.0]
def change
create_table :schedules do |t|
+ t.references :controller, null: false, foreign_key: true
t.integer :hour
t.integer :minute
t.boolean :is_active
@@ -8,6 +9,6 @@ class CreateSchedules < ActiveRecord::Migration[8.0]
t.timestamps
end
- add_index :schedules, [ :hour, :minute ], unique: true
+ add_index :schedules, [ :controller_id, :hour, :minute ], unique: true
end
end
diff --git a/db/schema.rb b/db/schema.rb
index cab8406..4dba5a7 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,13 +11,24 @@
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[8.0].define(version: 2025_04_16_131440) do
+ create_table "controllers", force: :cascade do |t|
+ t.string "name"
+ t.integer "station_id"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
create_table "schedules", force: :cascade do |t|
+ t.integer "controller_id", null: false
t.integer "hour"
t.integer "minute"
t.boolean "is_active"
t.float "temperature"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
- t.index ["hour", "minute"], name: "index_schedules_on_hour_and_minute", unique: true
+ t.index ["controller_id", "hour", "minute"], name: "index_schedules_on_controller_id_and_hour_and_minute", unique: true
+ t.index ["controller_id"], name: "index_schedules_on_controller_id"
end
+
+ add_foreign_key "schedules", "controllers"
end
diff --git a/db/seeds.rb b/db/seeds.rb
index 953e2e0..22289d3 100644
--- a/db/seeds.rb
+++ b/db/seeds.rb
@@ -8,6 +8,10 @@
# MovieGenre.find_or_create_by!(name: genre_name)
# end
+Controller.create(name: "3번방", station_id: 7)
+Controller.create(name: "2번방", station_id: 8)
+
(0..23).each do | h |
- Schedule.create!(hour: h, minute: 0, is_active: true, temperature: 15.0)
+ Schedule.create!(controller_id: 1, hour: h, minute: 0, is_active: true, temperature: 15.0)
+ Schedule.create!(controller_id: 2, hour: h, minute: 0, is_active: true, temperature: 15.0)
end
diff --git a/on_off.rb b/on_off.rb
index 9dcf8e8..998757f 100644
--- a/on_off.rb
+++ b/on_off.rb
@@ -1,10 +1,11 @@
require "rmodbus"
require "ccutrer-serialport"
-value = ARGV[0]&.to_i
+controller_id = ARGV[0]&.to_i
+value = ARGV[1]&.to_i
ModBus::RTUClient.new("/dev/ttyUSB0", 9600) do |cl|
- cl.with_slave(7) do |slave|
+ cl.with_slave(controller_id) do |slave|
regs = slave.holding_registers
regs[22] = value
sleep 0.1
diff --git a/serial.rb b/serial.rb
index 5ea916a..dd9d4a9 100644
--- a/serial.rb
+++ b/serial.rb
@@ -1,10 +1,11 @@
require "rmodbus"
require "ccutrer-serialport"
-value = ARGV[0]&.to_i
+controller_id = ARGV[0]&.to_i
+value = ARGV[1]&.to_i
ModBus::RTUClient.new("/dev/ttyUSB0", 9600) do |cl|
- cl.with_slave(7) do |slave|
+ cl.with_slave(controller_id) do |slave|
regs = slave.holding_registers
regs[2] = value
sleep 0.1
diff --git a/test.rb b/test.rb
new file mode 100644
index 0000000..5ea916a
--- /dev/null
+++ b/test.rb
@@ -0,0 +1,12 @@
+require "rmodbus"
+require "ccutrer-serialport"
+
+value = ARGV[0]&.to_i
+
+ModBus::RTUClient.new("/dev/ttyUSB0", 9600) do |cl|
+ cl.with_slave(7) do |slave|
+ regs = slave.holding_registers
+ regs[2] = value
+ sleep 0.1
+ end
+end
diff --git a/test/fixtures/controllers.yml b/test/fixtures/controllers.yml
new file mode 100644
index 0000000..d7a3329
--- /dev/null
+++ b/test/fixtures/controllers.yml
@@ -0,0 +1,11 @@
+# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
+
+# This model initially had no columns defined. If you add columns to the
+# model remove the "{}" from the fixture names and add the columns immediately
+# below each fixture, per the syntax in the comments below
+#
+one: {}
+# column: value
+#
+two: {}
+# column: value
diff --git a/test/models/controller_test.rb b/test/models/controller_test.rb
new file mode 100644
index 0000000..c355ca7
--- /dev/null
+++ b/test/models/controller_test.rb
@@ -0,0 +1,7 @@
+require "test_helper"
+
+class ControllerTest < ActiveSupport::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end